Fix toolbar's mute buttons when starting muted
The toolbar's mute buttons depict respective features/base/media states. However, (un)muting is practically carried out by features/base/tracks. When the mobile app enters a conference configured to invite the joining participant to mute themselves, the tracks would be muted but the toolbar's mute buttons would not reflect that.
This commit is contained in:
parent
f271eb4610
commit
4997ae79e3
|
@ -34,7 +34,7 @@ export function disposeLib() {
|
||||||
*/
|
*/
|
||||||
export function initLib() {
|
export function initLib() {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const config = getState()['features/base/lib'].config;
|
const config = getState()['features/base/lib-jitsi-meet'].config;
|
||||||
|
|
||||||
if (!config) {
|
if (!config) {
|
||||||
throw new Error('Cannot initialize lib-jitsi-meet without config');
|
throw new Error('Cannot initialize lib-jitsi-meet without config');
|
||||||
|
|
|
@ -19,26 +19,23 @@ import { SET_CONFIG } from './actionTypes';
|
||||||
MiddlewareRegistry.register(store => next => action => {
|
MiddlewareRegistry.register(store => next => action => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case PARTICIPANT_LEFT:
|
case PARTICIPANT_LEFT:
|
||||||
if (action.participant.local) {
|
action.participant.local && store.dispatch(disposeLib());
|
||||||
store.dispatch(disposeLib());
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SET_CONFIG: {
|
case SET_CONFIG: {
|
||||||
const { dispatch, getState } = store;
|
const { dispatch, getState } = store;
|
||||||
const libInitialized = getState()['features/base/lib'].initialized;
|
const initialized
|
||||||
|
= getState()['features/base/lib-jitsi-meet'].initialized;
|
||||||
|
|
||||||
// XXX If we already have config, that means new config is coming, which
|
// XXX If we already have config, that means new config is coming, which
|
||||||
// means that we should dispose instance of lib initialized with
|
// means that we should dispose instance of lib initialized with
|
||||||
// previous config first.
|
// previous config first.
|
||||||
// TODO Currently 'disposeLib' actually does not dispose lib-jitsi-meet.
|
// TODO Currently 'disposeLib' actually does not dispose lib-jitsi-meet.
|
||||||
// This functionality should be implemented.
|
// This functionality should be implemented.
|
||||||
const promise = libInitialized
|
const promise
|
||||||
? dispatch(disposeLib())
|
= initialized ? dispatch(disposeLib()) : Promise.resolve();
|
||||||
: Promise.resolve();
|
|
||||||
|
|
||||||
promise
|
promise.then(dispatch(initLib()));
|
||||||
.then(dispatch(initLib()));
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {
|
||||||
} from './actionTypes';
|
} from './actionTypes';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initial state of 'features/base/lib'.
|
* Initial state of 'features/base/lib-jitsi-meet'.
|
||||||
*
|
*
|
||||||
* @type {{
|
* @type {{
|
||||||
* initializationError: null,
|
* initializationError: null,
|
||||||
|
@ -31,7 +31,7 @@ const INITIAL_STATE = {
|
||||||
};
|
};
|
||||||
|
|
||||||
ReducerRegistry.register(
|
ReducerRegistry.register(
|
||||||
'features/base/lib',
|
'features/base/lib-jitsi-meet',
|
||||||
(state = INITIAL_STATE, action) => {
|
(state = INITIAL_STATE, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case LIB_DISPOSED:
|
case LIB_DISPOSED:
|
||||||
|
|
|
@ -42,15 +42,10 @@ function resetInitialMediaState(store) {
|
||||||
const { dispatch, getState } = store;
|
const { dispatch, getState } = store;
|
||||||
const state = getState()['features/base/media'];
|
const state = getState()['features/base/media'];
|
||||||
|
|
||||||
if (state.audio.muted) {
|
state.audio.muted && dispatch(audioMutedChanged(false));
|
||||||
dispatch(audioMutedChanged(false));
|
(state.video.facingMode !== CAMERA_FACING_MODE.USER)
|
||||||
}
|
&& dispatch(cameraFacingModeChanged(CAMERA_FACING_MODE.USER));
|
||||||
if (state.video.facingMode !== CAMERA_FACING_MODE.USER) {
|
state.video.muted && dispatch(videoMutedChanged(false));
|
||||||
dispatch(cameraFacingModeChanged(CAMERA_FACING_MODE.USER));
|
|
||||||
}
|
|
||||||
if (state.video.muted) {
|
|
||||||
dispatch(videoMutedChanged(false));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -72,14 +72,18 @@ export function getTracksByMediaType(tracks, mediaType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mute or unmute local track if any.
|
* Mutes or unmutes a specific <tt>JitsiLocalTrack</tt>. If the muted state of
|
||||||
|
* the specified <tt>track</tt> is already in accord with the specified
|
||||||
|
* <tt>muted</tt> value, then does nothing.
|
||||||
*
|
*
|
||||||
* @param {JitsiLocalTrack} track - Track instance.
|
* @param {JitsiLocalTrack} track - The <tt>JitsiLocalTrack</tt> to mute or
|
||||||
* @param {boolean} muted - If audio stream should be muted or unmuted.
|
* unmute.
|
||||||
|
* @param {boolean} muted - If the specified <tt>track</tt> is to be muted, then
|
||||||
|
* <tt>true</tt>; otherwise, <tt>false</tt>.
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
export function setTrackMuted(track, muted) {
|
export function setTrackMuted(track, muted) {
|
||||||
if (!track) {
|
if (track.isMuted() === muted) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,11 @@ import {
|
||||||
} from '../lib-jitsi-meet';
|
} from '../lib-jitsi-meet';
|
||||||
import {
|
import {
|
||||||
AUDIO_MUTED_CHANGED,
|
AUDIO_MUTED_CHANGED,
|
||||||
|
audioMutedChanged,
|
||||||
CAMERA_FACING_MODE_CHANGED,
|
CAMERA_FACING_MODE_CHANGED,
|
||||||
MEDIA_TYPE,
|
MEDIA_TYPE,
|
||||||
VIDEO_MUTED_CHANGED
|
VIDEO_MUTED_CHANGED,
|
||||||
|
videoMutedChanged
|
||||||
} from '../media';
|
} from '../media';
|
||||||
import { MiddlewareRegistry } from '../redux';
|
import { MiddlewareRegistry } from '../redux';
|
||||||
|
|
||||||
|
@ -14,6 +16,7 @@ import {
|
||||||
createLocalTracks,
|
createLocalTracks,
|
||||||
destroyLocalTracks
|
destroyLocalTracks
|
||||||
} from './actions';
|
} from './actions';
|
||||||
|
import { TRACK_UPDATED } from './actionTypes';
|
||||||
import {
|
import {
|
||||||
getLocalTrack,
|
getLocalTrack,
|
||||||
setTrackMuted
|
setTrackMuted
|
||||||
|
@ -50,6 +53,9 @@ MiddlewareRegistry.register(store => next => action => {
|
||||||
store.dispatch(destroyLocalTracks());
|
store.dispatch(destroyLocalTracks());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TRACK_UPDATED:
|
||||||
|
return _trackUpdated(store, next, action);
|
||||||
|
|
||||||
case VIDEO_MUTED_CHANGED:
|
case VIDEO_MUTED_CHANGED:
|
||||||
_mutedChanged(store, action, MEDIA_TYPE.VIDEO);
|
_mutedChanged(store, action, MEDIA_TYPE.VIDEO);
|
||||||
break;
|
break;
|
||||||
|
@ -58,6 +64,22 @@ MiddlewareRegistry.register(store => next => action => {
|
||||||
return next(action);
|
return next(action);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the local track associated with a specific <tt>MEDIA_TYPE</tt> in a
|
||||||
|
* specific Redux store.
|
||||||
|
*
|
||||||
|
* @param {Store} store - The Redux store from which the local track associated
|
||||||
|
* with the specified <tt>mediaType</tt> is to be retrieved.
|
||||||
|
* @param {MEDIA_TYPE} mediaType - The <tt>MEDIA_TYPE</tt> of the local track to
|
||||||
|
* be retrieved from the specified <tt>store</tt>.
|
||||||
|
* @private
|
||||||
|
* @returns {Track} The local <tt>Track</tt> associated with the specified
|
||||||
|
* <tt>mediaType</tt> in the specified <tt>store</tt>.
|
||||||
|
*/
|
||||||
|
function _getLocalTrack(store, mediaType) {
|
||||||
|
return getLocalTrack(store.getState()['features/base/tracks'], mediaType);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mutes or unmutes a local track with a specific media type.
|
* Mutes or unmutes a local track with a specific media type.
|
||||||
*
|
*
|
||||||
|
@ -70,8 +92,67 @@ MiddlewareRegistry.register(store => next => action => {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function _mutedChanged(store, action, mediaType) {
|
function _mutedChanged(store, action, mediaType) {
|
||||||
const tracks = store.getState()['features/base/tracks'];
|
const localTrack = _getLocalTrack(store, mediaType);
|
||||||
const localTrack = getLocalTrack(tracks, mediaType);
|
|
||||||
|
|
||||||
localTrack && setTrackMuted(localTrack.jitsiTrack, action.muted);
|
localTrack && setTrackMuted(localTrack.jitsiTrack, action.muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intercepts the action <tt>TRACK_UPDATED</tt> in order to synchronize the
|
||||||
|
* muted states of the local tracks of features/base/tracks with the muted
|
||||||
|
* states of features/base/media.
|
||||||
|
*
|
||||||
|
* @param {Store} store - The Redux store in which the specified <tt>action</tt>
|
||||||
|
* is being dispatched.
|
||||||
|
* @param {Dispatch} next - The Redux dispatch function to dispatch the
|
||||||
|
* specified <tt>action</tt> to the specified <tt>store</tt>.
|
||||||
|
* @param {Action} action - The Redux action <tt>TRACK_UPDATED</tt> which is
|
||||||
|
* being dispatched in the specified <tt>store</tt>.
|
||||||
|
* @private
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function _trackUpdated(store, next, action) {
|
||||||
|
// Determine the muted state of the local track before the update.
|
||||||
|
const track = action.track;
|
||||||
|
let mediaType;
|
||||||
|
let oldMuted;
|
||||||
|
|
||||||
|
if ('muted' in track) {
|
||||||
|
// XXX The return value of JitsiTrack.getType() is of type MEDIA_TYPE
|
||||||
|
// that happens to be compatible with the type MEDIA_TYPE defined by
|
||||||
|
// jitsi-meet-react.
|
||||||
|
mediaType = track.jitsiTrack.getType();
|
||||||
|
|
||||||
|
const localTrack = _getLocalTrack(store, mediaType);
|
||||||
|
|
||||||
|
if (localTrack) {
|
||||||
|
oldMuted = localTrack.muted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = next(action);
|
||||||
|
|
||||||
|
if (typeof oldMuted !== 'undefined') {
|
||||||
|
// Determine the muted state of the local track after the update. If the
|
||||||
|
// muted states before and after the update differ, then the respective
|
||||||
|
// media state should by synchronized.
|
||||||
|
const localTrack = _getLocalTrack(store, mediaType);
|
||||||
|
|
||||||
|
if (localTrack) {
|
||||||
|
const newMuted = localTrack.muted;
|
||||||
|
|
||||||
|
if (oldMuted !== newMuted) {
|
||||||
|
switch (mediaType) {
|
||||||
|
case MEDIA_TYPE.AUDIO:
|
||||||
|
store.dispatch(audioMutedChanged(newMuted));
|
||||||
|
break;
|
||||||
|
case MEDIA_TYPE.VIDEO:
|
||||||
|
store.dispatch(videoMutedChanged(newMuted));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -49,9 +49,8 @@ MiddlewareRegistry.register(store => next => action => {
|
||||||
action.track.jitsiTrack);
|
action.track.jitsiTrack);
|
||||||
const participantId = state['features/largeVideo'].participantId;
|
const participantId = state['features/largeVideo'].participantId;
|
||||||
|
|
||||||
if (track.participantId === participantId) {
|
(track.participantId === participantId)
|
||||||
store.dispatch(selectParticipant());
|
&& store.dispatch(selectParticipant());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue