Add/fix JSDoc comments

While reviewing "[PREVIEW|RN]: Handle getUserMedia in progress" I
discovered JSDoc comments which could be improved. They are not
necessarily 100% related to the PR.
This commit is contained in:
Lyubo Marinov 2017-11-13 16:10:54 -06:00
parent f37a12c332
commit decf9c4991
6 changed files with 139 additions and 129 deletions

View File

@ -211,12 +211,12 @@ export function conferenceLeft(conference: Object) {
} }
/** /**
* Attaches any pre-existing local media to the conference, before * Adds any existing local tracks to a specific conference before the conference
* the conference will be joined. Then signals the intention of the application * is joined. Then signals the intention of the application to have the local
* to have the local participant join a specific conference. * participant join the specified conference.
* *
* @param {JitsiConference} conference - The JitsiConference instance the * @param {JitsiConference} conference - The {@code JitsiConference} instance
* local participant will (try to) join. * the local participant will (try to) join.
* @returns {Function} * @returns {Function}
*/ */
function _conferenceWillJoin(conference: Object) { function _conferenceWillJoin(conference: Object) {

View File

@ -1,6 +1,6 @@
/** /**
* Action for when a track has been added to the conference, * The type of redux action dispatched when a track has been (locally or
* local or remote. * remotely) added to the conference.
* *
* { * {
* type: TRACK_ADDED, * type: TRACK_ADDED,
@ -10,18 +10,19 @@
export const TRACK_ADDED = Symbol('TRACK_ADDED'); export const TRACK_ADDED = Symbol('TRACK_ADDED');
/** /**
* Action triggered when a local track starts being created through the WebRTC * The type of redux action dispatched when a local track starts being created
* getUserMedia call. It will include extra 'gumProcess' field which is * via a WebRTC {@code getUserMedia} call. The action's payload includes an
* a Promise with extra 'cancel' method which can be used to cancel the process. * extra {@code gumProcess} property which is a {@code Promise} with an extra
* Canceling will result in disposing any JitsiLocalTrack returned by the GUM * {@code cancel} method which can be used to cancel the process. Canceling will
* callback. There will be TRACK_CREATE_CANCELED event instead of track * result in disposing any {@code JitsiLocalTrack} returned by the
* added/gum failed events. * {@code getUserMedia} callback. There will be a {@code TRACK_CREATE_CANCELED}
* action instead of a {@code TRACK_ADDED} or {@code TRACK_CREATE_ERROR} action.
* *
* { * {
* type: TRACK_BEING_CREATED * type: TRACK_BEING_CREATED
* track: { * track: {
* gumProcess: Promise with a `cancel` method to cancel the process,
* local: true, * local: true,
* gumProcess: Promise with cancel() method to abort,
* mediaType: MEDIA_TYPE * mediaType: MEDIA_TYPE
* } * }
* } * }
@ -29,8 +30,9 @@ export const TRACK_ADDED = Symbol('TRACK_ADDED');
export const TRACK_BEING_CREATED = Symbol('TRACK_BEING_CREATED'); export const TRACK_BEING_CREATED = Symbol('TRACK_BEING_CREATED');
/** /**
* Action sent when canceled GUM process completes either successfully or with * The type of redux action dispatched when a canceled {@code getUserMedia}
* an error (error is ignored and track is immediately disposed if created). * process completes either successfully or with an error (the error is ignored
* and the track is immediately disposed if it has been created).
* *
* { * {
* type: TRACK_CREATE_CANCELED, * type: TRACK_CREATE_CANCELED,
@ -40,7 +42,8 @@ export const TRACK_BEING_CREATED = Symbol('TRACK_BEING_CREATED');
export const TRACK_CREATE_CANCELED = Symbol('TRACK_CREATE_CANCELED'); export const TRACK_CREATE_CANCELED = Symbol('TRACK_CREATE_CANCELED');
/** /**
* Action sent when GUM fails with an error other than permission denied. * The type of redux action dispatched when {@code getUserMedia} fails with an
* error (such as permission denied).
* *
* { * {
* type: TRACK_CREATE_ERROR, * type: TRACK_CREATE_ERROR,
@ -51,8 +54,8 @@ export const TRACK_CREATE_CANCELED = Symbol('TRACK_CREATE_CANCELED');
export const TRACK_CREATE_ERROR = Symbol('TRACK_CREATE_ERROR'); export const TRACK_CREATE_ERROR = Symbol('TRACK_CREATE_ERROR');
/** /**
* Action for when a track has been removed from the conference, * The type of redux action dispatched when a track has been (locally or
* local or remote. * remotely) removed from the conference.
* *
* { * {
* type: TRACK_REMOVED, * type: TRACK_REMOVED,
@ -62,7 +65,7 @@ export const TRACK_CREATE_ERROR = Symbol('TRACK_CREATE_ERROR');
export const TRACK_REMOVED = Symbol('TRACK_REMOVED'); export const TRACK_REMOVED = Symbol('TRACK_REMOVED');
/** /**
* Action for when a track properties were updated. * The type of redux action dispatched when a track's properties were updated.
* *
* { * {
* type: TRACK_UPDATED, * type: TRACK_UPDATED,

View File

@ -37,7 +37,7 @@ export function createDesiredLocalTracks(...desiredTypes) {
const { audio, video } = state['features/base/media']; const { audio, video } = state['features/base/media'];
audio.muted || desiredTypes.push(MEDIA_TYPE.AUDIO); audio.muted || desiredTypes.push(MEDIA_TYPE.AUDIO);
Boolean(video.muted) || desiredTypes.push(MEDIA_TYPE.VIDEO); video.muted || desiredTypes.push(MEDIA_TYPE.VIDEO);
} }
const availableTypes const availableTypes
@ -85,44 +85,52 @@ export function createLocalTracksA(options = {}) {
.find(t => t.local && t.mediaType === device)) { .find(t => t.local && t.mediaType === device)) {
throw new Error(`Local track for ${device} already exists`); throw new Error(`Local track for ${device} already exists`);
} }
const gumProcess = createLocalTracksF(
{
cameraDeviceId: options.cameraDeviceId,
devices: [ device ],
facingMode: options.facingMode || CAMERA_FACING_MODE.USER,
micDeviceId: options.micDeviceId
},
/* firePermissionPromptIsShownEvent */ false,
store)
.then(
localTracks => {
// Because GUM is called for 1 device (which is actually
// a media type 'audio','video', 'screen' etc.) we should
// not get more than one JitsiTrack.
if (localTracks.length !== 1) {
throw new Error(
'Expected exactly 1 track, but was '
+ `given ${localTracks.length} tracks`
+ `for device: ${device}.`);
}
if (gumProcess.canceled) { const gumProcess
return _disposeTracks(localTracks) = createLocalTracksF(
.then( {
() => cameraDeviceId: options.cameraDeviceId,
dispatch( devices: [ device ],
_trackCreateCanceled(device))); facingMode:
} options.facingMode || CAMERA_FACING_MODE.USER,
micDeviceId: options.micDeviceId
},
/* firePermissionPromptIsShownEvent */ false,
store)
.then(
localTracks => {
// Because GUM is called for 1 device (which is actually
// a media type 'audio', 'video', 'screen', etc.) we
// should not get more than one JitsiTrack.
if (localTracks.length !== 1) {
throw new Error(
`Expected exactly 1 track, but was given ${
localTracks.length} tracks for device: ${
device}.`);
}
return dispatch(trackAdded(localTracks[0])); if (gumProcess.canceled) {
}, return _disposeTracks(localTracks)
// eslint-disable-next-line no-confusing-arrow .then(() =>
reason => dispatch(_trackCreateCanceled(device)));
dispatch( }
gumProcess.canceled
? _trackCreateCanceled(device)
: _onCreateLocalTracksRejected(reason, device)));
return dispatch(trackAdded(localTracks[0]));
},
reason =>
dispatch(
gumProcess.canceled
? _trackCreateCanceled(device)
: _onCreateLocalTracksRejected(
reason,
device)));
/**
* Cancels the {@code getUserMedia} process represented by this
* {@code Promise}.
*
* @returns {Promise} This {@code Promise} i.e. {@code gumProcess}.
*/
gumProcess.cancel = () => { gumProcess.cancel = () => {
gumProcess.canceled = true; gumProcess.canceled = true;
@ -132,8 +140,8 @@ export function createLocalTracksA(options = {}) {
dispatch({ dispatch({
type: TRACK_BEING_CREATED, type: TRACK_BEING_CREATED,
track: { track: {
local: true,
gumProcess, gumProcess,
local: true,
mediaType: device mediaType: device
} }
}); });
@ -151,9 +159,9 @@ export function destroyLocalTracks() {
return (dispatch, getState) => { return (dispatch, getState) => {
// First wait until any getUserMedia in progress is settled and then get // First wait until any getUserMedia in progress is settled and then get
// rid of all local tracks. // rid of all local tracks.
_cancelAllGumInProgress(getState) _cancelGUMProcesses(getState)
.then( .then(() =>
() => dispatch( dispatch(
_disposeAndRemoveTracks( _disposeAndRemoveTracks(
getState()['features/base/tracks'] getState()['features/base/tracks']
.filter(t => t.local) .filter(t => t.local)
@ -366,49 +374,27 @@ function _addTracks(tracks) {
} }
/** /**
* Signals that track create operation for given media track has been canceled. * Cancels and waits for any {@code getUserMedia} process/currently in progress
* Will clean up local track stub from the Redux state which holds the * to complete/settle.
* 'gumProcess' reference.
* *
* @param {MEDIA_TYPE} mediaType - The type of the media for which the track was * @param {Function} getState - The redux store {@code getState} function used
* being created. * to obtain the state.
* @returns {{
* type,
* trackType: MEDIA_TYPE
* }}
* @private * @private
* @returns {Promise} - A {@code Promise} resolved once all
* {@code gumProcess.cancel()} {@code Promise}s are settled because all we care
* about here is to be sure that the {@code getUserMedia} callbacks have
* completed (i.e. returned from the native side).
*/ */
function _trackCreateCanceled(mediaType) { function _cancelGUMProcesses(getState) {
return {
type: TRACK_CREATE_CANCELED,
trackType: mediaType
};
}
/**
* Cancels and waits for any get user media operations currently in progress to
* complete.
*
* @param {Function} getState - The Redux store {@code getState} method used to
* obtain the state.
* @returns {Promise} - A Promise resolved once all {@code gumProcess.cancel}
* Promises are settled. That is when they are either resolved or rejected,
* because all we care about here is to be sure that get user media callbacks
* have completed (returned from the native side).
* @private
*/
function _cancelAllGumInProgress(getState) {
// FIXME use logger
const logError const logError
= error => = error =>
console.error('gumProcess.cancel failed', JSON.stringify(error)); logger.error('gumProcess.cancel failed', JSON.stringify(error));
return Promise.all( return Promise.all(
getState()['features/base/tracks'] getState()['features/base/tracks']
.filter(t => t.local) .filter(t => t.local)
.map( .map(({ gumProcess }) =>
t => t.gumProcess gumProcess && gumProcess.cancel().catch(logError)));
&& t.gumProcess.cancel().catch(logError)));
} }
/** /**
@ -421,15 +407,15 @@ function _cancelAllGumInProgress(getState) {
export function _disposeAndRemoveTracks(tracks) { export function _disposeAndRemoveTracks(tracks) {
return dispatch => return dispatch =>
_disposeTracks(tracks) _disposeTracks(tracks)
.then( .then(() =>
() => Promise.all(tracks.map(t => dispatch(trackRemoved(t))))); Promise.all(tracks.map(t => dispatch(trackRemoved(t)))));
} }
/** /**
* Disposes passed tracks. * Disposes passed tracks.
* *
* @param {(JitsiLocalTrack|JitsiRemoteTrack)[]} tracks - List of tracks. * @param {(JitsiLocalTrack|JitsiRemoteTrack)[]} tracks - List of tracks.
* @protected * @private
* @returns {Promise} - A Promise resolved once {@link JitsiTrack.dispose()} is * @returns {Promise} - A Promise resolved once {@link JitsiTrack.dispose()} is
* done for every track from the list. * done for every track from the list.
*/ */
@ -438,13 +424,12 @@ function _disposeTracks(tracks) {
tracks.map(t => tracks.map(t =>
t.dispose() t.dispose()
.catch(err => { .catch(err => {
// Track might be already disposed so ignore such an // Track might be already disposed so ignore such an error.
// error. Of course, re-throw any other error(s). // Of course, re-throw any other error(s).
if (err.name !== JitsiTrackErrors.TRACK_IS_DISPOSED) { if (err.name !== JitsiTrackErrors.TRACK_IS_DISPOSED) {
throw err; throw err;
} }
}) })));
));
} }
/** /**
@ -496,7 +481,8 @@ function _onCreateLocalTracksRejected({ gum }, device) {
} }
/** /**
* Returns true if the provided JitsiTrack should be rendered as a mirror. * Returns true if the provided {@code JitsiTrack} should be rendered as a
* mirror.
* *
* We only want to show a video in mirrored mode when: * We only want to show a video in mirrored mode when:
* 1) The video source is local, and not remote. * 1) The video source is local, and not remote.
@ -524,3 +510,23 @@ function _shouldMirror(track) {
// but that may not be the case tomorrow. // but that may not be the case tomorrow.
&& track.getCameraFacingMode() === CAMERA_FACING_MODE.USER); && track.getCameraFacingMode() === CAMERA_FACING_MODE.USER);
} }
/**
* Signals that track create operation for given media track has been canceled.
* Will clean up local track stub from the redux state which holds the
* {@code gumProcess} reference.
*
* @param {MEDIA_TYPE} mediaType - The type of the media for which the track was
* being created.
* @private
* @returns {{
* type,
* trackType: MEDIA_TYPE
* }}
*/
function _trackCreateCanceled(mediaType) {
return {
type: TRACK_CREATE_CANCELED,
trackType: mediaType
};
}

View File

@ -110,21 +110,21 @@ export function getLocalTrack(tracks, mediaType) {
} }
/** /**
* Returns an array containing local tracks. Local tracks without valid * Returns an array containing the local tracks with a (valid)
* JitsiTrack will not be included in the list. * {@code JitsiTrack}.
* *
* @param {Track[]} tracks - An array of all local tracks. * @param {Track[]} tracks - An array containing all local tracks.
* @returns {Track[]} * @returns {Track[]}
*/ */
export function getLocalTracks(tracks) { export function getLocalTracks(tracks) {
// XXX A local track is considered ready only once it has 'jitsiTrack' field // XXX A local track is considered ready only once it has its `jitsiTrack`
// set by the TRACK_ADDED action. Until then there is a stub added just // property set by the `TRACK_ADDED` action. Until then there is a stub
// before get user media call with a cancellable 'gumInProgress' field which // added just before the `getUserMedia` call with a cancellable
// then can be used to destroy the track that has not yet been added to // `gumInProgress` property which then can be used to destroy the track that
// the Redux store. Once GUM is cancelled it will never make it to the store // has not yet been added to the redux store. Once GUM is cancelled, it will
// nor there will be any TRACK_ADDED/TRACK_REMOVED related events fired for // never make it to the store nor there will be any
// it. // `TRACK_ADDED`/`TRACK_REMOVED` actions dispatched for it.
return tracks.filter(t => t.local && t.jitsiTrack); return tracks.filter(t => t.local && t.jitsiTrack);
} }
@ -215,7 +215,7 @@ export function setTrackMuted(track, muted) {
return track[f]().catch(error => { return track[f]().catch(error => {
// FIXME emit mute failed, so that the app can show error dialog // FIXME Emit mute failed, so that the app can show error dialog.
console.error(`set track ${f} failed`, error); console.error(`set track ${f} failed`, error);
}); });
} }

View File

@ -12,23 +12,24 @@ import {
/** /**
* @typedef {Object} Track * @typedef {Object} Track
* @property {(JitsiLocalTrack|JitsiRemoteTrack)} [jitsiTrack] - JitsiTrack * @property {(JitsiLocalTrack|JitsiRemoteTrack)} [jitsiTrack] - The associated
* instance. Optional for local tracks if those are being created (GUM in * {@code JitsiTrack} instance. Optional for local tracks if those are still
* progress). * being created (i.e. {@code getUserMedia} is still in progress).
* @property {boolean} local=false - If track is local. * @property {Promise} [gumProcess] - If a local track is still being created,
* @property {Promise} [gumProcess] - if local track is being created it * it will have no {@code JitsiTrack}, but a {@code gumProcess} set to a
* will have no JitsiTrack, but a 'gumProcess' set to a Promise with and extra * {@code Promise} with and extra {@code cancel()}.
* cancel(). * @property {boolean} local=false - If the track is local.
* @property {MEDIA_TYPE} mediaType=false - Media type of track. * @property {MEDIA_TYPE} mediaType=false - The media type of the track.
* @property {boolean} mirror=false - The indicator which determines whether the * @property {boolean} mirror=false - The indicator which determines whether the
* display/rendering of the track should be mirrored. It only makes sense in the * display/rendering of the track should be mirrored. It only makes sense in the
* context of video (at least at the time of this writing). * context of video (at least at the time of this writing).
* @property {boolean} muted=false - If track is muted. * @property {boolean} muted=false - If the track is muted.
* @property {(string|undefined)} participantId - ID of participant whom this * @property {(string|undefined)} participantId - The ID of the participant whom
* track belongs to. * the track belongs to.
* @property {boolean} videoStarted=false - If video track has already started * @property {boolean} videoStarted=false - If the video track has already
* to play. * started to play.
* @property {(VIDEO_TYPE|undefined)} videoType - Type of video track if any. * @property {(VIDEO_TYPE|undefined)} videoType - The type of video track if
* any.
*/ */
/** /**

View File

@ -95,9 +95,9 @@ class MuteRemoteParticipantDialog extends Component {
/** /**
* Renders the content of the dialog. * Renders the content of the dialog.
* *
* @returns {Component} the react component, which is the view of the dialog
* content
* @private * @private
* @returns {Component} The React {@code Component} which is the view of the
* dialog content.
*/ */
_renderContent() { _renderContent() {
const { t } = this.props; const { t } = this.props;