fix(prejoin): Store prejoin tracks in 'features/base/tracks'
This commit is contained in:
parent
ec6ed6e8ec
commit
4f169988a3
|
@ -118,10 +118,7 @@ import { mediaPermissionPromptVisibilityChanged } from './react/features/overlay
|
||||||
import { suspendDetected } from './react/features/power-monitor';
|
import { suspendDetected } from './react/features/power-monitor';
|
||||||
import {
|
import {
|
||||||
initPrejoin,
|
initPrejoin,
|
||||||
isPrejoinPageEnabled,
|
isPrejoinPageEnabled
|
||||||
isPrejoinPageVisible,
|
|
||||||
replacePrejoinAudioTrack,
|
|
||||||
replacePrejoinVideoTrack
|
|
||||||
} from './react/features/prejoin';
|
} from './react/features/prejoin';
|
||||||
import { createRnnoiseProcessorPromise } from './react/features/rnnoise';
|
import { createRnnoiseProcessorPromise } from './react/features/rnnoise';
|
||||||
import { toggleScreenshotCaptureEffect } from './react/features/screenshot-capture';
|
import { toggleScreenshotCaptureEffect } from './react/features/screenshot-capture';
|
||||||
|
@ -1409,18 +1406,6 @@ export default {
|
||||||
useVideoStream(newStream) {
|
useVideoStream(newStream) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
_replaceLocalVideoTrackQueue.enqueue(onFinish => {
|
_replaceLocalVideoTrackQueue.enqueue(onFinish => {
|
||||||
/**
|
|
||||||
* When the prejoin page is visible there is no conference object
|
|
||||||
* created. The prejoin tracks are managed separately,
|
|
||||||
* so this updates the prejoin video track.
|
|
||||||
*/
|
|
||||||
if (isPrejoinPageVisible(APP.store.getState())) {
|
|
||||||
return APP.store.dispatch(replacePrejoinVideoTrack(newStream))
|
|
||||||
.then(resolve)
|
|
||||||
.catch(reject)
|
|
||||||
.then(onFinish);
|
|
||||||
}
|
|
||||||
|
|
||||||
APP.store.dispatch(
|
APP.store.dispatch(
|
||||||
replaceLocalTrack(this.localVideo, newStream, room))
|
replaceLocalTrack(this.localVideo, newStream, room))
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
@ -1474,18 +1459,6 @@ export default {
|
||||||
useAudioStream(newStream) {
|
useAudioStream(newStream) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
_replaceLocalAudioTrackQueue.enqueue(onFinish => {
|
_replaceLocalAudioTrackQueue.enqueue(onFinish => {
|
||||||
/**
|
|
||||||
* When the prejoin page is visible there is no conference object
|
|
||||||
* created. The prejoin tracks are managed separately,
|
|
||||||
* so this updates the prejoin audio stream.
|
|
||||||
*/
|
|
||||||
if (isPrejoinPageVisible(APP.store.getState())) {
|
|
||||||
return APP.store.dispatch(replacePrejoinAudioTrack(newStream))
|
|
||||||
.then(resolve)
|
|
||||||
.catch(reject)
|
|
||||||
.then(onFinish);
|
|
||||||
}
|
|
||||||
|
|
||||||
APP.store.dispatch(
|
APP.store.dispatch(
|
||||||
replaceLocalTrack(this.localAudio, newStream, room))
|
replaceLocalTrack(this.localAudio, newStream, room))
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|
|
@ -35,6 +35,10 @@
|
||||||
cursor: initial;
|
cursor: initial;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background-color: #a4b8d1;
|
background-color: #a4b8d1;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #a4b8d1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
|
|
|
@ -4,6 +4,17 @@ import { toState } from '../redux';
|
||||||
|
|
||||||
import { VIDEO_MUTISM_AUTHORITY } from './constants';
|
import { VIDEO_MUTISM_AUTHORITY } from './constants';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether audio is currently muted.
|
||||||
|
*
|
||||||
|
* @param {Function|Object} stateful - The redux store, state, or
|
||||||
|
* {@code getState} function.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isAudioMuted(stateful: Function | Object) {
|
||||||
|
return Boolean(toState(stateful)['features/base/media'].audio.muted);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether video is currently muted by the audio-only authority.
|
* Determines whether video is currently muted by the audio-only authority.
|
||||||
*
|
*
|
||||||
|
|
|
@ -9,7 +9,7 @@ export * from './functions.any';
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export function getCurrentCameraDeviceId(state: Object) {
|
export function getCurrentCameraDeviceId(state: Object) {
|
||||||
return state['features/base/settings'].cameraDeviceId;
|
return getDeviceIdByType(state, 'isVideoTrack');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,7 +19,7 @@ export function getCurrentCameraDeviceId(state: Object) {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export function getCurrentMicDeviceId(state: Object) {
|
export function getCurrentMicDeviceId(state: Object) {
|
||||||
return state['features/base/settings'].micDeviceId;
|
return getDeviceIdByType(state, 'isAudioTrack');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,6 +32,22 @@ export function getCurrentOutputDeviceId(state: Object) {
|
||||||
return state['features/base/settings'].audioOutputDeviceId;
|
return state['features/base/settings'].audioOutputDeviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the deviceId for the corresponding local track type.
|
||||||
|
*
|
||||||
|
* @param {Object} state - The state of the application.
|
||||||
|
* @param {string} isType - Can be 'isVideoTrack' | 'isAudioTrack'.
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function getDeviceIdByType(state: Object, isType: string) {
|
||||||
|
const [ deviceId ] = state['features/base/tracks']
|
||||||
|
.map(t => t.jitsiTrack)
|
||||||
|
.filter(t => t && t.isLocal() && t[isType]())
|
||||||
|
.map(t => t.getDeviceId());
|
||||||
|
|
||||||
|
return deviceId || '';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the saved display name.
|
* Returns the saved display name.
|
||||||
*
|
*
|
||||||
|
|
|
@ -267,14 +267,29 @@ export function toggleScreensharing() {
|
||||||
* @returns {Function}
|
* @returns {Function}
|
||||||
*/
|
*/
|
||||||
export function replaceLocalTrack(oldTrack, newTrack, conference) {
|
export function replaceLocalTrack(oldTrack, newTrack, conference) {
|
||||||
return (dispatch, getState) => {
|
return async (dispatch, getState) => {
|
||||||
conference
|
conference
|
||||||
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
|| (conference = getState()['features/base/conference'].conference);
|
|| (conference = getState()['features/base/conference'].conference);
|
||||||
|
|
||||||
return conference.replaceTrack(oldTrack, newTrack)
|
if (conference) {
|
||||||
.then(() => {
|
await conference.replaceTrack(oldTrack, newTrack);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dispatch(replaceStoredTracks(oldTrack, newTrack));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces a stored track with another.
|
||||||
|
*
|
||||||
|
* @param {JitsiLocalTrack|null} oldTrack - The track to dispose.
|
||||||
|
* @param {JitsiLocalTrack|null} newTrack - The track to use instead.
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
function replaceStoredTracks(oldTrack, newTrack) {
|
||||||
|
return dispatch => {
|
||||||
// We call dispose after doing the replace because dispose will
|
// We call dispose after doing the replace because dispose will
|
||||||
// try and do a new o/a after the track removes itself. Doing it
|
// try and do a new o/a after the track removes itself. Doing it
|
||||||
// after means the JitsiLocalTrack.conference is already
|
// after means the JitsiLocalTrack.conference is already
|
||||||
|
@ -317,7 +332,6 @@ export function replaceLocalTrack(oldTrack, newTrack, conference) {
|
||||||
return dispatch(_addTracks([ newTrack ]));
|
return dispatch(_addTracks([ newTrack ]));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -200,6 +200,18 @@ export function getLocalVideoType(tracks) {
|
||||||
return presenterTrack ? MEDIA_TYPE.PRESENTER : MEDIA_TYPE.VIDEO;
|
return presenterTrack ? MEDIA_TYPE.PRESENTER : MEDIA_TYPE.VIDEO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the stored local video track.
|
||||||
|
*
|
||||||
|
* @param {Object} state - The redux state.
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
export function getLocalJitsiVideoTrack(state) {
|
||||||
|
const track = getLocalVideoTrack(state['features/base/tracks']);
|
||||||
|
|
||||||
|
return track?.jitsiTrack;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns track of specified media type for specified participant id.
|
* Returns track of specified media type for specified participant id.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
import UIEvents from '../../../../service/UI/UIEvents';
|
import UIEvents from '../../../../service/UI/UIEvents';
|
||||||
import { hideNotification } from '../../notifications';
|
import { hideNotification } from '../../notifications';
|
||||||
|
import { isPrejoinPageVisible } from '../../prejoin/functions';
|
||||||
|
import { getAvailableDevices } from '../devices/actions';
|
||||||
import {
|
import {
|
||||||
CAMERA_FACING_MODE,
|
CAMERA_FACING_MODE,
|
||||||
MEDIA_TYPE,
|
MEDIA_TYPE,
|
||||||
|
@ -15,6 +17,7 @@ import {
|
||||||
import { MiddlewareRegistry } from '../redux';
|
import { MiddlewareRegistry } from '../redux';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
TRACK_ADDED,
|
||||||
TOGGLE_SCREENSHARING,
|
TOGGLE_SCREENSHARING,
|
||||||
TRACK_NO_DATA_FROM_SOURCE,
|
TRACK_NO_DATA_FROM_SOURCE,
|
||||||
TRACK_REMOVED,
|
TRACK_REMOVED,
|
||||||
|
@ -44,6 +47,15 @@ declare var APP: Object;
|
||||||
*/
|
*/
|
||||||
MiddlewareRegistry.register(store => next => action => {
|
MiddlewareRegistry.register(store => next => action => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
case TRACK_ADDED: {
|
||||||
|
// The devices list needs to be refreshed when no initial video permissions
|
||||||
|
// were granted and a local video track is added by umuting the video.
|
||||||
|
if (action.track.local) {
|
||||||
|
store.dispatch(getAvailableDevices());
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
case TRACK_NO_DATA_FROM_SOURCE: {
|
case TRACK_NO_DATA_FROM_SOURCE: {
|
||||||
const result = next(action);
|
const result = next(action);
|
||||||
|
|
||||||
|
@ -281,7 +293,7 @@ function _setMuted(store, { ensureTrack, authority, muted }, mediaType: MEDIA_TY
|
||||||
// anymore, unless it is muted by audioOnly.
|
// anymore, unless it is muted by audioOnly.
|
||||||
jitsiTrack && (jitsiTrack.videoType !== 'desktop' || isAudioOnly)
|
jitsiTrack && (jitsiTrack.videoType !== 'desktop' || isAudioOnly)
|
||||||
&& setTrackMuted(jitsiTrack, muted);
|
&& setTrackMuted(jitsiTrack, muted);
|
||||||
} else if (!muted && ensureTrack && typeof APP === 'undefined') {
|
} else if (!muted && ensureTrack && (typeof APP === 'undefined' || isPrejoinPageVisible(store.getState()))) {
|
||||||
// FIXME: This only runs on mobile now because web has its own way of
|
// FIXME: This only runs on mobile now because web has its own way of
|
||||||
// creating local tracks. Adjust the check once they are unified.
|
// creating local tracks. Adjust the check once they are unified.
|
||||||
store.dispatch(createLocalTracksA({ devices: [ mediaType ] }));
|
store.dispatch(createLocalTracksA({ devices: [ mediaType ] }));
|
||||||
|
|
|
@ -1,18 +1,3 @@
|
||||||
/**
|
|
||||||
* Action type to add a video track to the store.
|
|
||||||
*/
|
|
||||||
export const ADD_PREJOIN_VIDEO_TRACK = 'ADD_PREJOIN_VIDEO_TRACK';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action type to add an audio track to the store.
|
|
||||||
*/
|
|
||||||
export const ADD_PREJOIN_AUDIO_TRACK = 'ADD_PREJOIN_AUDIO_TRACK';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action type to add a content sharing track to the store.
|
|
||||||
*/
|
|
||||||
export const ADD_PREJOIN_CONTENT_SHARING_TRACK
|
|
||||||
= 'ADD_PREJOIN_CONTENT_SHARING_TRACK';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action type to signal the start of the conference.
|
* Action type to signal the start of the conference.
|
||||||
|
@ -68,13 +53,3 @@ export const SET_PREJOIN_DEVICE_ERRORS = 'SET_PREJOIN_DEVICE_ERRORS';
|
||||||
* Action type to set the visibility of the prejoin page.
|
* Action type to set the visibility of the prejoin page.
|
||||||
*/
|
*/
|
||||||
export const SET_PREJOIN_PAGE_VISIBILITY = 'SET_PREJOIN_PAGE_VISIBILITY';
|
export const SET_PREJOIN_PAGE_VISIBILITY = 'SET_PREJOIN_PAGE_VISIBILITY';
|
||||||
|
|
||||||
/**
|
|
||||||
* Action type to mute/unmute the video while on prejoin page.
|
|
||||||
*/
|
|
||||||
export const SET_PREJOIN_VIDEO_DISABLED = 'SET_PREJOIN_VIDEO_DISABLED';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action type to mute/unmute the video while on prejoin page.
|
|
||||||
*/
|
|
||||||
export const SET_PREJOIN_VIDEO_MUTED = 'SET_PREJOIN_VIDEO_MUTED';
|
|
||||||
|
|
|
@ -5,14 +5,17 @@ import uuid from 'uuid';
|
||||||
import { getRoomName } from '../base/conference';
|
import { getRoomName } from '../base/conference';
|
||||||
import { getDialOutStatusUrl, getDialOutUrl } from '../base/config/functions';
|
import { getDialOutStatusUrl, getDialOutUrl } from '../base/config/functions';
|
||||||
import { createLocalTrack } from '../base/lib-jitsi-meet';
|
import { createLocalTrack } from '../base/lib-jitsi-meet';
|
||||||
|
import {
|
||||||
|
getLocalAudioTrack,
|
||||||
|
getLocalVideoTrack,
|
||||||
|
trackAdded,
|
||||||
|
replaceLocalTrack
|
||||||
|
} from '../base/tracks';
|
||||||
import { openURLInBrowser } from '../base/util';
|
import { openURLInBrowser } from '../base/util';
|
||||||
import { executeDialOutRequest, executeDialOutStatusRequest, getDialInfoPageURL } from '../invite/functions';
|
import { executeDialOutRequest, executeDialOutStatusRequest, getDialInfoPageURL } from '../invite/functions';
|
||||||
import { showErrorNotification } from '../notifications';
|
import { showErrorNotification } from '../notifications';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ADD_PREJOIN_AUDIO_TRACK,
|
|
||||||
ADD_PREJOIN_CONTENT_SHARING_TRACK,
|
|
||||||
ADD_PREJOIN_VIDEO_TRACK,
|
|
||||||
PREJOIN_START_CONFERENCE,
|
PREJOIN_START_CONFERENCE,
|
||||||
SET_DEVICE_STATUS,
|
SET_DEVICE_STATUS,
|
||||||
SET_DIALOUT_COUNTRY,
|
SET_DIALOUT_COUNTRY,
|
||||||
|
@ -20,19 +23,13 @@ import {
|
||||||
SET_DIALOUT_STATUS,
|
SET_DIALOUT_STATUS,
|
||||||
SET_SKIP_PREJOIN,
|
SET_SKIP_PREJOIN,
|
||||||
SET_JOIN_BY_PHONE_DIALOG_VISIBLITY,
|
SET_JOIN_BY_PHONE_DIALOG_VISIBLITY,
|
||||||
SET_PREJOIN_AUDIO_DISABLED,
|
|
||||||
SET_PREJOIN_AUDIO_MUTED,
|
|
||||||
SET_PREJOIN_DEVICE_ERRORS,
|
SET_PREJOIN_DEVICE_ERRORS,
|
||||||
SET_PREJOIN_PAGE_VISIBILITY,
|
SET_PREJOIN_PAGE_VISIBILITY
|
||||||
SET_PREJOIN_VIDEO_DISABLED,
|
|
||||||
SET_PREJOIN_VIDEO_MUTED
|
|
||||||
} from './actionTypes';
|
} from './actionTypes';
|
||||||
import {
|
import {
|
||||||
getFullDialOutNumber,
|
getFullDialOutNumber,
|
||||||
getAudioTrack,
|
|
||||||
getDialOutConferenceUrl,
|
getDialOutConferenceUrl,
|
||||||
getDialOutCountry,
|
getDialOutCountry,
|
||||||
getVideoTrack,
|
|
||||||
isJoinByPhoneDialogVisible
|
isJoinByPhoneDialogVisible
|
||||||
} from './functions';
|
} from './functions';
|
||||||
import logger from './logger';
|
import logger from './logger';
|
||||||
|
@ -60,45 +57,6 @@ const STATUS_REQ_FREQUENCY = 2000;
|
||||||
*/
|
*/
|
||||||
const STATUS_REQ_CAP = 45;
|
const STATUS_REQ_CAP = 45;
|
||||||
|
|
||||||
/**
|
|
||||||
* Action used to add an audio track to the store.
|
|
||||||
*
|
|
||||||
* @param {Object} value - The track to be added.
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
export function addPrejoinAudioTrack(value: Object) {
|
|
||||||
return {
|
|
||||||
type: ADD_PREJOIN_AUDIO_TRACK,
|
|
||||||
value
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action used to add a video track to the store.
|
|
||||||
*
|
|
||||||
* @param {Object} value - The track to be added.
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
export function addPrejoinVideoTrack(value: Object) {
|
|
||||||
return {
|
|
||||||
type: ADD_PREJOIN_VIDEO_TRACK,
|
|
||||||
value
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action used to add a content sharing track to the store.
|
|
||||||
*
|
|
||||||
* @param {Object} value - The track to be added.
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
export function addPrejoinContentSharingTrack(value: Object) {
|
|
||||||
return {
|
|
||||||
type: ADD_PREJOIN_CONTENT_SHARING_TRACK,
|
|
||||||
value
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Polls for status change after dial out.
|
* Polls for status change after dial out.
|
||||||
* Changes dialog message based on response, closes the dialog if there is an error,
|
* Changes dialog message based on response, closes the dialog if there is an error,
|
||||||
|
@ -232,27 +190,10 @@ export function dialOut(onSuccess: Function, onFail: Function) {
|
||||||
*/
|
*/
|
||||||
export function initPrejoin(tracks: Object[], errors: Object) {
|
export function initPrejoin(tracks: Object[], errors: Object) {
|
||||||
return async function(dispatch: Function) {
|
return async function(dispatch: Function) {
|
||||||
const audioTrack = tracks.find(t => t.isAudioTrack());
|
|
||||||
const videoTrack = tracks.find(t => t.isVideoTrack());
|
|
||||||
|
|
||||||
dispatch(setPrejoinDeviceErrors(errors));
|
dispatch(setPrejoinDeviceErrors(errors));
|
||||||
|
|
||||||
if (audioTrack) {
|
|
||||||
dispatch(addPrejoinAudioTrack(audioTrack));
|
|
||||||
} else {
|
|
||||||
dispatch(setAudioDisabled());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (videoTrack) {
|
tracks.forEach(track => dispatch(trackAdded(track)));
|
||||||
if (videoTrack.videoType === 'desktop') {
|
|
||||||
dispatch(addPrejoinContentSharingTrack(videoTrack));
|
|
||||||
dispatch(setPrejoinVideoDisabled(true));
|
|
||||||
} else {
|
|
||||||
dispatch(addPrejoinVideoTrack(videoTrack));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dispatch(setPrejoinVideoDisabled(true));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,12 +216,12 @@ export function joinConference() {
|
||||||
*/
|
*/
|
||||||
export function joinConferenceWithoutAudio() {
|
export function joinConferenceWithoutAudio() {
|
||||||
return async function(dispatch: Function, getState: Function) {
|
return async function(dispatch: Function, getState: Function) {
|
||||||
const audioTrack = getAudioTrack(getState());
|
const tracks = getState()['features/base/tracks'];
|
||||||
|
const audioTrack = getLocalAudioTrack(tracks)?.jitsiTrack;
|
||||||
|
|
||||||
if (audioTrack) {
|
if (audioTrack) {
|
||||||
await dispatch(replacePrejoinAudioTrack(null));
|
await dispatch(replaceLocalTrack(audioTrack, null));
|
||||||
}
|
}
|
||||||
dispatch(setAudioDisabled());
|
|
||||||
dispatch(joinConference());
|
dispatch(joinConference());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -301,21 +242,6 @@ export function openDialInPage() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Replaces the existing audio track with a new one.
|
|
||||||
*
|
|
||||||
* @param {Object} track - The new track.
|
|
||||||
* @returns {Function}
|
|
||||||
*/
|
|
||||||
export function replacePrejoinAudioTrack(track: Object) {
|
|
||||||
return async (dispatch: Function, getState: Function) => {
|
|
||||||
const oldTrack = getAudioTrack(getState());
|
|
||||||
|
|
||||||
oldTrack && await oldTrack.dispose();
|
|
||||||
dispatch(addPrejoinAudioTrack(track));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new audio track based on a device id and replaces the current one.
|
* Creates a new audio track based on a device id and replaces the current one.
|
||||||
*
|
*
|
||||||
|
@ -323,11 +249,13 @@ export function replacePrejoinAudioTrack(track: Object) {
|
||||||
* @returns {Function}
|
* @returns {Function}
|
||||||
*/
|
*/
|
||||||
export function replaceAudioTrackById(deviceId: string) {
|
export function replaceAudioTrackById(deviceId: string) {
|
||||||
return async (dispatch: Function) => {
|
return async (dispatch: Function, getState: Function) => {
|
||||||
try {
|
try {
|
||||||
const track = await createLocalTrack('audio', deviceId);
|
const tracks = getState()['features/base/tracks'];
|
||||||
|
const newTrack = await createLocalTrack('audio', deviceId);
|
||||||
|
const oldTrack = getLocalAudioTrack(tracks)?.jitsiTrack;
|
||||||
|
|
||||||
dispatch(replacePrejoinAudioTrack(track));
|
dispatch(replaceLocalTrack(oldTrack, newTrack));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
dispatch(setDeviceStatusWarning('prejoin.audioTrackError'));
|
dispatch(setDeviceStatusWarning('prejoin.audioTrackError'));
|
||||||
logger.log('Error replacing audio track', err);
|
logger.log('Error replacing audio track', err);
|
||||||
|
@ -335,21 +263,6 @@ export function replaceAudioTrackById(deviceId: string) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Replaces the existing video track with a new one.
|
|
||||||
*
|
|
||||||
* @param {Object} track - The new track.
|
|
||||||
* @returns {Function}
|
|
||||||
*/
|
|
||||||
export function replacePrejoinVideoTrack(track: Object) {
|
|
||||||
return async (dispatch: Function, getState: Function) => {
|
|
||||||
const oldTrack = getVideoTrack(getState());
|
|
||||||
|
|
||||||
oldTrack && await oldTrack.dispose();
|
|
||||||
dispatch(addPrejoinVideoTrack(track));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new video track based on a device id and replaces the current one.
|
* Creates a new video track based on a device id and replaces the current one.
|
||||||
*
|
*
|
||||||
|
@ -357,11 +270,13 @@ export function replacePrejoinVideoTrack(track: Object) {
|
||||||
* @returns {Function}
|
* @returns {Function}
|
||||||
*/
|
*/
|
||||||
export function replaceVideoTrackById(deviceId: Object) {
|
export function replaceVideoTrackById(deviceId: Object) {
|
||||||
return async (dispatch: Function) => {
|
return async (dispatch: Function, getState: Function) => {
|
||||||
try {
|
try {
|
||||||
const track = await createLocalTrack('video', deviceId);
|
const tracks = getState()['features/base/tracks'];
|
||||||
|
const newTrack = await createLocalTrack('video', deviceId);
|
||||||
|
const oldTrack = getLocalVideoTrack(tracks)?.jitsiTrack;
|
||||||
|
|
||||||
dispatch(replacePrejoinVideoTrack(track));
|
dispatch(replaceLocalTrack(oldTrack, newTrack));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
dispatch(setDeviceStatusWarning('prejoin.videoTrackError'));
|
dispatch(setDeviceStatusWarning('prejoin.videoTrackError'));
|
||||||
logger.log('Error replacing video track', err);
|
logger.log('Error replacing video track', err);
|
||||||
|
@ -369,58 +284,6 @@ export function replaceVideoTrackById(deviceId: Object) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action used to mark audio muted.
|
|
||||||
*
|
|
||||||
* @param {boolean} value - True for muted.
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
export function setPrejoinAudioMuted(value: boolean) {
|
|
||||||
return {
|
|
||||||
type: SET_PREJOIN_AUDIO_MUTED,
|
|
||||||
value
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action used to mark video disabled.
|
|
||||||
*
|
|
||||||
* @param {boolean} value - True for muted.
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
export function setPrejoinVideoDisabled(value: boolean) {
|
|
||||||
return {
|
|
||||||
type: SET_PREJOIN_VIDEO_DISABLED,
|
|
||||||
value
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action used to mark video muted.
|
|
||||||
*
|
|
||||||
* @param {boolean} value - True for muted.
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
export function setPrejoinVideoMuted(value: boolean) {
|
|
||||||
return {
|
|
||||||
type: SET_PREJOIN_VIDEO_MUTED,
|
|
||||||
value
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action used to mark audio as disabled.
|
|
||||||
*
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
export function setAudioDisabled() {
|
|
||||||
return {
|
|
||||||
type: SET_PREJOIN_AUDIO_DISABLED
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the device status as OK with the corresponding text.
|
* Sets the device status as OK with the corresponding text.
|
||||||
*
|
*
|
||||||
|
|
|
@ -6,9 +6,11 @@ import React, { Component } from 'react';
|
||||||
import { getRoomName } from '../../base/conference';
|
import { getRoomName } from '../../base/conference';
|
||||||
import { translate } from '../../base/i18n';
|
import { translate } from '../../base/i18n';
|
||||||
import { Icon, IconPhone, IconVolumeOff } from '../../base/icons';
|
import { Icon, IconPhone, IconVolumeOff } from '../../base/icons';
|
||||||
|
import { isVideoMutedByUser } from '../../base/media';
|
||||||
import { ActionButton, InputField, PreMeetingScreen } from '../../base/premeeting';
|
import { ActionButton, InputField, PreMeetingScreen } from '../../base/premeeting';
|
||||||
import { connect } from '../../base/redux';
|
import { connect } from '../../base/redux';
|
||||||
import { getDisplayName, updateSettings } from '../../base/settings';
|
import { getDisplayName, updateSettings } from '../../base/settings';
|
||||||
|
import { getLocalJitsiVideoTrack } from '../../base/tracks';
|
||||||
import {
|
import {
|
||||||
joinConference as joinConferenceAction,
|
joinConference as joinConferenceAction,
|
||||||
joinConferenceWithoutAudio as joinConferenceWithoutAudioAction,
|
joinConferenceWithoutAudio as joinConferenceWithoutAudioAction,
|
||||||
|
@ -16,11 +18,9 @@ import {
|
||||||
setJoinByPhoneDialogVisiblity as setJoinByPhoneDialogVisiblityAction
|
setJoinByPhoneDialogVisiblity as setJoinByPhoneDialogVisiblityAction
|
||||||
} from '../actions';
|
} from '../actions';
|
||||||
import {
|
import {
|
||||||
getActiveVideoTrack,
|
|
||||||
isJoinByPhoneButtonVisible,
|
isJoinByPhoneButtonVisible,
|
||||||
isDeviceStatusVisible,
|
isDeviceStatusVisible,
|
||||||
isJoinByPhoneDialogVisible,
|
isJoinByPhoneDialogVisible
|
||||||
isPrejoinVideoMuted
|
|
||||||
} from '../functions';
|
} from '../functions';
|
||||||
|
|
||||||
import JoinByPhoneDialog from './dialogs/JoinByPhoneDialog';
|
import JoinByPhoneDialog from './dialogs/JoinByPhoneDialog';
|
||||||
|
@ -315,8 +315,8 @@ function mapStateToProps(state): Object {
|
||||||
roomName: getRoomName(state),
|
roomName: getRoomName(state),
|
||||||
showDialog: isJoinByPhoneDialogVisible(state),
|
showDialog: isJoinByPhoneDialogVisible(state),
|
||||||
hasJoinByPhoneButton: isJoinByPhoneButtonVisible(state),
|
hasJoinByPhoneButton: isJoinByPhoneButtonVisible(state),
|
||||||
showCameraPreview: !isPrejoinVideoMuted(state),
|
showCameraPreview: !isVideoMutedByUser(state),
|
||||||
videoTrack: getActiveVideoTrack(state)
|
videoTrack: getLocalJitsiVideoTrack(state)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,25 +2,7 @@
|
||||||
|
|
||||||
import { getRoomName } from '../base/conference';
|
import { getRoomName } from '../base/conference';
|
||||||
import { getDialOutStatusUrl, getDialOutUrl } from '../base/config/functions';
|
import { getDialOutStatusUrl, getDialOutUrl } from '../base/config/functions';
|
||||||
|
import { isAudioMuted, isVideoMutedByUser } from '../base/media';
|
||||||
/**
|
|
||||||
* Mutes or unmutes a track.
|
|
||||||
*
|
|
||||||
* @param {Object} track - The track to be configured.
|
|
||||||
* @param {boolean} shouldMute - If it should mute or not.
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
function applyMuteOptionsToTrack(track, shouldMute) {
|
|
||||||
if (track.isMuted() === shouldMute) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldMute) {
|
|
||||||
return track.mute();
|
|
||||||
}
|
|
||||||
|
|
||||||
return track.unmute();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selector for the visibility of the 'join by phone' button.
|
* Selector for the visibility of the 'join by phone' button.
|
||||||
|
@ -39,73 +21,8 @@ export function isJoinByPhoneButtonVisible(state: Object): boolean {
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function isDeviceStatusVisible(state: Object): boolean {
|
export function isDeviceStatusVisible(state: Object): boolean {
|
||||||
return !((isAudioDisabled(state) && isPrejoinVideoDisabled(state))
|
return !(isAudioMuted(state) && isVideoMutedByUser(state))
|
||||||
|| (isPrejoinAudioMuted(state) && isPrejoinVideoMuted(state)));
|
&& !state['features/base/config'].startSilent;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Selector for getting the active video/content sharing track.
|
|
||||||
*
|
|
||||||
* @param {Object} state - The state of the app.
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
export function getActiveVideoTrack(state: Object): Object {
|
|
||||||
const track = getVideoTrack(state) || getContentSharingTrack(state);
|
|
||||||
|
|
||||||
if (track && track.isActive()) {
|
|
||||||
return track;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list with all the prejoin tracks configured according to
|
|
||||||
* user's preferences.
|
|
||||||
*
|
|
||||||
* @param {Object} state - The state of the app.
|
|
||||||
* @returns {Promise<Object[]>}
|
|
||||||
*/
|
|
||||||
export async function getAllPrejoinConfiguredTracks(state: Object): Promise<Object[]> {
|
|
||||||
const tracks = [];
|
|
||||||
const audioTrack = getAudioTrack(state);
|
|
||||||
const videoTrack = getVideoTrack(state);
|
|
||||||
const csTrack = getContentSharingTrack(state);
|
|
||||||
|
|
||||||
if (csTrack) {
|
|
||||||
tracks.push(csTrack);
|
|
||||||
} else if (videoTrack) {
|
|
||||||
await applyMuteOptionsToTrack(videoTrack, isPrejoinVideoMuted(state));
|
|
||||||
tracks.push(videoTrack);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (audioTrack) {
|
|
||||||
await applyMuteOptionsToTrack(audioTrack, isPrejoinAudioMuted(state));
|
|
||||||
isPrejoinAudioMuted(state) && audioTrack.mute();
|
|
||||||
tracks.push(audioTrack);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tracks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Selector for getting the prejoin audio track.
|
|
||||||
*
|
|
||||||
* @param {Object} state - The state of the app.
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
export function getAudioTrack(state: Object): Object {
|
|
||||||
return state['features/prejoin']?.audioTrack;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Selector for getting the prejoin content sharing track.
|
|
||||||
*
|
|
||||||
* @param {Object} state - The state of the app.
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
export function getContentSharingTrack(state: Object): Object {
|
|
||||||
return state['features/prejoin']?.contentSharingTrack;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -181,36 +98,6 @@ export function getFullDialOutNumber(state: Object): string {
|
||||||
return `+${country.dialCode}${dialOutNumber}`;
|
return `+${country.dialCode}${dialOutNumber}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Selector for getting the prejoin video track.
|
|
||||||
*
|
|
||||||
* @param {Object} state - The state of the app.
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
export function getVideoTrack(state: Object): Object {
|
|
||||||
return state['features/prejoin']?.videoTrack;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Selector for getting the mute status of the prejoin audio.
|
|
||||||
*
|
|
||||||
* @param {Object} state - The state of the app.
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
export function isPrejoinAudioMuted(state: Object): boolean {
|
|
||||||
return state['features/prejoin']?.audioMuted;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Selector for getting the mute status of the prejoin video.
|
|
||||||
*
|
|
||||||
* @param {Object} state - The state of the app.
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
export function isPrejoinVideoMuted(state: Object): boolean {
|
|
||||||
return state['features/prejoin']?.videoMuted;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selector for getting the error if any while creating streams.
|
* Selector for getting the error if any while creating streams.
|
||||||
*
|
*
|
||||||
|
@ -221,26 +108,6 @@ export function getRawError(state: Object): string {
|
||||||
return state['features/prejoin']?.rawError;
|
return state['features/prejoin']?.rawError;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Selector for getting state of the prejoin audio.
|
|
||||||
*
|
|
||||||
* @param {Object} state - The state of the app.
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
export function isAudioDisabled(state: Object): Object {
|
|
||||||
return state['features/prejoin']?.audioDisabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Selector for getting state of the prejoin video.
|
|
||||||
*
|
|
||||||
* @param {Object} state - The state of the app.
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
export function isPrejoinVideoDisabled(state: Object): Object {
|
|
||||||
return state['features/prejoin']?.videoDisabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selector for getting the visiblity state for the 'JoinByPhoneDialog'.
|
* Selector for getting the visiblity state for the 'JoinByPhoneDialog'.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,16 +1,9 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import { SET_AUDIO_MUTED, SET_VIDEO_MUTED } from '../base/media';
|
|
||||||
import { MiddlewareRegistry } from '../base/redux';
|
import { MiddlewareRegistry } from '../base/redux';
|
||||||
import { updateSettings } from '../base/settings';
|
import { updateSettings } from '../base/settings';
|
||||||
|
|
||||||
import {
|
import { PREJOIN_START_CONFERENCE } from './actionTypes';
|
||||||
ADD_PREJOIN_AUDIO_TRACK,
|
|
||||||
ADD_PREJOIN_VIDEO_TRACK,
|
|
||||||
PREJOIN_START_CONFERENCE
|
|
||||||
} from './actionTypes';
|
|
||||||
import { setPrejoinAudioMuted, setPrejoinVideoMuted } from './actions';
|
|
||||||
import { getAllPrejoinConfiguredTracks } from './functions';
|
|
||||||
|
|
||||||
declare var APP: Object;
|
declare var APP: Object;
|
||||||
|
|
||||||
|
@ -22,62 +15,22 @@ declare var APP: Object;
|
||||||
*/
|
*/
|
||||||
MiddlewareRegistry.register(store => next => async action => {
|
MiddlewareRegistry.register(store => next => async action => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ADD_PREJOIN_AUDIO_TRACK: {
|
|
||||||
const { value: audioTrack } = action;
|
|
||||||
|
|
||||||
if (audioTrack) {
|
|
||||||
store.dispatch(
|
|
||||||
updateSettings({
|
|
||||||
micDeviceId: audioTrack.getDeviceId()
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ADD_PREJOIN_VIDEO_TRACK: {
|
|
||||||
const { value: videoTrack } = action;
|
|
||||||
|
|
||||||
if (videoTrack) {
|
|
||||||
store.dispatch(
|
|
||||||
updateSettings({
|
|
||||||
cameraDeviceId: videoTrack.getDeviceId()
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case PREJOIN_START_CONFERENCE: {
|
case PREJOIN_START_CONFERENCE: {
|
||||||
const { getState, dispatch } = store;
|
const { getState, dispatch } = store;
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const { userSelectedSkipPrejoin } = state['features/prejoin'];
|
const { userSelectedSkipPrejoin } = state['features/prejoin'];
|
||||||
|
const tracks = state['features/base/tracks'];
|
||||||
|
|
||||||
userSelectedSkipPrejoin && dispatch(updateSettings({
|
userSelectedSkipPrejoin && dispatch(updateSettings({
|
||||||
userSelectedSkipPrejoin
|
userSelectedSkipPrejoin
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
APP.conference.prejoinStart(tracks.map(t => t.jitsiTrack));
|
||||||
const tracks = await getAllPrejoinConfiguredTracks(state);
|
|
||||||
|
|
||||||
APP.conference.prejoinStart(tracks);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SET_AUDIO_MUTED: {
|
|
||||||
store.dispatch(setPrejoinAudioMuted(Boolean(action.muted)));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case SET_VIDEO_MUTED: {
|
|
||||||
store.dispatch(setPrejoinVideoMuted(Boolean(action.muted)));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return next(action);
|
return next(action);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,28 +1,17 @@
|
||||||
import { ReducerRegistry } from '../base/redux';
|
import { ReducerRegistry } from '../base/redux';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ADD_PREJOIN_AUDIO_TRACK,
|
|
||||||
ADD_PREJOIN_CONTENT_SHARING_TRACK,
|
|
||||||
ADD_PREJOIN_VIDEO_TRACK,
|
|
||||||
SET_DEVICE_STATUS,
|
SET_DEVICE_STATUS,
|
||||||
SET_DIALOUT_NUMBER,
|
SET_DIALOUT_NUMBER,
|
||||||
SET_DIALOUT_COUNTRY,
|
SET_DIALOUT_COUNTRY,
|
||||||
SET_DIALOUT_STATUS,
|
SET_DIALOUT_STATUS,
|
||||||
SET_JOIN_BY_PHONE_DIALOG_VISIBLITY,
|
SET_JOIN_BY_PHONE_DIALOG_VISIBLITY,
|
||||||
SET_SKIP_PREJOIN,
|
SET_SKIP_PREJOIN,
|
||||||
SET_PREJOIN_AUDIO_DISABLED,
|
|
||||||
SET_PREJOIN_AUDIO_MUTED,
|
|
||||||
SET_PREJOIN_DEVICE_ERRORS,
|
SET_PREJOIN_DEVICE_ERRORS,
|
||||||
SET_PREJOIN_PAGE_VISIBILITY,
|
SET_PREJOIN_PAGE_VISIBILITY
|
||||||
SET_PREJOIN_VIDEO_DISABLED,
|
|
||||||
SET_PREJOIN_VIDEO_MUTED
|
|
||||||
} from './actionTypes';
|
} from './actionTypes';
|
||||||
|
|
||||||
const DEFAULT_STATE = {
|
const DEFAULT_STATE = {
|
||||||
audioDisabled: false,
|
|
||||||
audioMuted: false,
|
|
||||||
audioTrack: null,
|
|
||||||
contentSharingTrack: null,
|
|
||||||
country: '',
|
country: '',
|
||||||
deviceStatusText: 'prejoin.configuringDevices',
|
deviceStatusText: 'prejoin.configuringDevices',
|
||||||
deviceStatusType: 'ok',
|
deviceStatusType: 'ok',
|
||||||
|
@ -37,10 +26,7 @@ const DEFAULT_STATE = {
|
||||||
rawError: '',
|
rawError: '',
|
||||||
showPrejoin: true,
|
showPrejoin: true,
|
||||||
showJoinByPhoneDialog: false,
|
showJoinByPhoneDialog: false,
|
||||||
userSelectedSkipPrejoin: false,
|
userSelectedSkipPrejoin: false
|
||||||
videoTrack: null,
|
|
||||||
videoDisabled: false,
|
|
||||||
videoMuted: false
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,26 +35,6 @@ const DEFAULT_STATE = {
|
||||||
ReducerRegistry.register(
|
ReducerRegistry.register(
|
||||||
'features/prejoin', (state = DEFAULT_STATE, action) => {
|
'features/prejoin', (state = DEFAULT_STATE, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ADD_PREJOIN_AUDIO_TRACK: {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
audioTrack: action.value
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
case ADD_PREJOIN_CONTENT_SHARING_TRACK: {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
contentSharingTrack: action.value
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
case ADD_PREJOIN_VIDEO_TRACK: {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
videoTrack: action.value
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
case SET_SKIP_PREJOIN: {
|
case SET_SKIP_PREJOIN: {
|
||||||
return {
|
return {
|
||||||
|
@ -83,25 +49,6 @@ ReducerRegistry.register(
|
||||||
showPrejoin: action.value
|
showPrejoin: action.value
|
||||||
};
|
};
|
||||||
|
|
||||||
case SET_PREJOIN_VIDEO_DISABLED: {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
videoDisabled: action.value
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
case SET_PREJOIN_VIDEO_MUTED:
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
videoMuted: action.value
|
|
||||||
};
|
|
||||||
|
|
||||||
case SET_PREJOIN_AUDIO_MUTED:
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
audioMuted: action.value
|
|
||||||
};
|
|
||||||
|
|
||||||
case SET_PREJOIN_DEVICE_ERRORS: {
|
case SET_PREJOIN_DEVICE_ERRORS: {
|
||||||
const status = getStatusFromErrors(action.value);
|
const status = getStatusFromErrors(action.value);
|
||||||
|
|
||||||
|
@ -119,13 +66,6 @@ ReducerRegistry.register(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
case SET_PREJOIN_AUDIO_DISABLED: {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
audioDisabled: true
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
case SET_DIALOUT_NUMBER: {
|
case SET_DIALOUT_NUMBER: {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
|
|
@ -12,11 +12,6 @@ import { connect } from '../../base/redux';
|
||||||
import { AbstractAudioMuteButton } from '../../base/toolbox';
|
import { AbstractAudioMuteButton } from '../../base/toolbox';
|
||||||
import type { AbstractButtonProps } from '../../base/toolbox';
|
import type { AbstractButtonProps } from '../../base/toolbox';
|
||||||
import { isLocalTrackMuted } from '../../base/tracks';
|
import { isLocalTrackMuted } from '../../base/tracks';
|
||||||
import {
|
|
||||||
isPrejoinAudioMuted,
|
|
||||||
isAudioDisabled,
|
|
||||||
isPrejoinPageVisible
|
|
||||||
} from '../../prejoin/functions';
|
|
||||||
import { muteLocal } from '../../remote-video-menu/actions';
|
import { muteLocal } from '../../remote-video-menu/actions';
|
||||||
|
|
||||||
declare var APP: Object;
|
declare var APP: Object;
|
||||||
|
@ -154,18 +149,8 @@ class AudioMuteButton extends AbstractAudioMuteButton<Props, *> {
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
function _mapStateToProps(state): Object {
|
function _mapStateToProps(state): Object {
|
||||||
let _audioMuted;
|
const _audioMuted = isLocalTrackMuted(state['features/base/tracks'], MEDIA_TYPE.AUDIO);
|
||||||
let _disabled;
|
const _disabled = state['features/base/config'].startSilent;
|
||||||
|
|
||||||
if (isPrejoinPageVisible(state)) {
|
|
||||||
_audioMuted = isPrejoinAudioMuted(state);
|
|
||||||
_disabled = state['features/base/config'].startSilent;
|
|
||||||
} else {
|
|
||||||
const tracks = state['features/base/tracks'];
|
|
||||||
|
|
||||||
_audioMuted = isLocalTrackMuted(tracks, MEDIA_TYPE.AUDIO);
|
|
||||||
_disabled = state['features/base/config'].startSilent || isAudioDisabled(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_audioMuted,
|
_audioMuted,
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {
|
||||||
sendAnalytics
|
sendAnalytics
|
||||||
} from '../../analytics';
|
} from '../../analytics';
|
||||||
import { setAudioOnly } from '../../base/audio-only';
|
import { setAudioOnly } from '../../base/audio-only';
|
||||||
|
import { hasAvailableDevices } from '../../base/devices';
|
||||||
import { translate } from '../../base/i18n';
|
import { translate } from '../../base/i18n';
|
||||||
import {
|
import {
|
||||||
VIDEO_MUTISM_AUTHORITY,
|
VIDEO_MUTISM_AUTHORITY,
|
||||||
|
@ -18,11 +19,6 @@ import { connect } from '../../base/redux';
|
||||||
import { AbstractVideoMuteButton } from '../../base/toolbox';
|
import { AbstractVideoMuteButton } from '../../base/toolbox';
|
||||||
import type { AbstractButtonProps } from '../../base/toolbox';
|
import type { AbstractButtonProps } from '../../base/toolbox';
|
||||||
import { getLocalVideoType, isLocalVideoTrackMuted } from '../../base/tracks';
|
import { getLocalVideoType, isLocalVideoTrackMuted } from '../../base/tracks';
|
||||||
import {
|
|
||||||
isPrejoinPageVisible,
|
|
||||||
isPrejoinVideoDisabled,
|
|
||||||
isPrejoinVideoMuted
|
|
||||||
} from '../../prejoin/functions';
|
|
||||||
|
|
||||||
declare var APP: Object;
|
declare var APP: Object;
|
||||||
|
|
||||||
|
@ -191,19 +187,12 @@ class VideoMuteButton extends AbstractVideoMuteButton<Props, *> {
|
||||||
function _mapStateToProps(state): Object {
|
function _mapStateToProps(state): Object {
|
||||||
const { enabled: audioOnly } = state['features/base/audio-only'];
|
const { enabled: audioOnly } = state['features/base/audio-only'];
|
||||||
const tracks = state['features/base/tracks'];
|
const tracks = state['features/base/tracks'];
|
||||||
let _videoMuted = isLocalVideoTrackMuted(tracks);
|
|
||||||
let _videoDisabled = false;
|
|
||||||
|
|
||||||
if (isPrejoinPageVisible(state)) {
|
|
||||||
_videoMuted = isPrejoinVideoMuted(state);
|
|
||||||
_videoDisabled = isPrejoinVideoDisabled(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_audioOnly: Boolean(audioOnly),
|
_audioOnly: Boolean(audioOnly),
|
||||||
_videoDisabled,
|
_videoDisabled: !hasAvailableDevices(state, 'videoInput'),
|
||||||
_videoMediaType: getLocalVideoType(tracks),
|
_videoMediaType: getLocalVideoType(tracks),
|
||||||
_videoMuted
|
_videoMuted: isLocalVideoTrackMuted(tracks)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { IconArrowDown } from '../../../base/icons';
|
||||||
import JitsiMeetJS from '../../../base/lib-jitsi-meet/_';
|
import JitsiMeetJS from '../../../base/lib-jitsi-meet/_';
|
||||||
import { connect } from '../../../base/redux';
|
import { connect } from '../../../base/redux';
|
||||||
import { ToolboxButtonWithIcon } from '../../../base/toolbox';
|
import { ToolboxButtonWithIcon } from '../../../base/toolbox';
|
||||||
|
import { getLocalJitsiVideoTrack } from '../../../base/tracks';
|
||||||
import { getMediaPermissionPromptVisibility } from '../../../overlay';
|
import { getMediaPermissionPromptVisibility } from '../../../overlay';
|
||||||
import { toggleVideoSettings, VideoSettingsPopup } from '../../../settings';
|
import { toggleVideoSettings, VideoSettingsPopup } from '../../../settings';
|
||||||
import { isVideoSettingsButtonDisabled } from '../../functions';
|
import { isVideoSettingsButtonDisabled } from '../../functions';
|
||||||
|
@ -24,6 +25,11 @@ type Props = {
|
||||||
*/
|
*/
|
||||||
permissionPromptVisibility: boolean,
|
permissionPromptVisibility: boolean,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether there is a video track or not.
|
||||||
|
*/
|
||||||
|
hasVideoTrack: boolean,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the button should be disabled
|
* If the button should be disabled
|
||||||
*/
|
*/
|
||||||
|
@ -66,6 +72,17 @@ class VideoSettingsButton extends Component<Props, State> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the settings icon is disabled.
|
||||||
|
*
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
_isIconDisabled() {
|
||||||
|
const { hasVideoTrack, isDisabled } = this.props;
|
||||||
|
|
||||||
|
return (!this.state.hasPermissions || isDisabled) && !hasVideoTrack;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates device permissions.
|
* Updates device permissions.
|
||||||
*
|
*
|
||||||
|
@ -116,14 +133,13 @@ class VideoSettingsButton extends Component<Props, State> {
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
const { isDisabled, onVideoOptionsClick, visible } = this.props;
|
const { onVideoOptionsClick, visible } = this.props;
|
||||||
const iconDisabled = !this.state.hasPermissions || isDisabled;
|
|
||||||
|
|
||||||
return visible ? (
|
return visible ? (
|
||||||
<VideoSettingsPopup>
|
<VideoSettingsPopup>
|
||||||
<ToolboxButtonWithIcon
|
<ToolboxButtonWithIcon
|
||||||
icon = { IconArrowDown }
|
icon = { IconArrowDown }
|
||||||
iconDisabled = { iconDisabled }
|
iconDisabled = { this._isIconDisabled() }
|
||||||
onIconClick = { onVideoOptionsClick }>
|
onIconClick = { onVideoOptionsClick }>
|
||||||
<VideoMuteButton />
|
<VideoMuteButton />
|
||||||
</ToolboxButtonWithIcon>
|
</ToolboxButtonWithIcon>
|
||||||
|
@ -140,6 +156,7 @@ class VideoSettingsButton extends Component<Props, State> {
|
||||||
*/
|
*/
|
||||||
function mapStateToProps(state) {
|
function mapStateToProps(state) {
|
||||||
return {
|
return {
|
||||||
|
hasVideoTrack: Boolean(getLocalJitsiVideoTrack(state)),
|
||||||
isDisabled: isVideoSettingsButtonDisabled(state),
|
isDisabled: isVideoSettingsButtonDisabled(state),
|
||||||
permissionPromptVisibility: getMediaPermissionPromptVisibility(state)
|
permissionPromptVisibility: getMediaPermissionPromptVisibility(state)
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import { hasAvailableDevices } from '../base/devices';
|
import { hasAvailableDevices } from '../base/devices';
|
||||||
import {
|
|
||||||
isAudioDisabled,
|
|
||||||
isPrejoinPageVisible,
|
|
||||||
isPrejoinVideoDisabled
|
|
||||||
} from '../prejoin';
|
|
||||||
|
|
||||||
declare var interfaceConfig: Object;
|
declare var interfaceConfig: Object;
|
||||||
|
|
||||||
|
@ -60,12 +55,9 @@ export function isToolboxVisible(state: Object) {
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function isAudioSettingsButtonDisabled(state: Object) {
|
export function isAudioSettingsButtonDisabled(state: Object) {
|
||||||
const devicesMissing = !hasAvailableDevices(state, 'audioInput')
|
return (!hasAvailableDevices(state, 'audioInput')
|
||||||
&& !hasAvailableDevices(state, 'audioOutput');
|
&& !hasAvailableDevices(state, 'audioOutput'))
|
||||||
|
|| state['features/base/config'].startSilent;
|
||||||
return isPrejoinPageVisible(state)
|
|
||||||
? devicesMissing || isAudioDisabled(state)
|
|
||||||
: devicesMissing;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,9 +67,5 @@ export function isAudioSettingsButtonDisabled(state: Object) {
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function isVideoSettingsButtonDisabled(state: Object) {
|
export function isVideoSettingsButtonDisabled(state: Object) {
|
||||||
const devicesMissing = !hasAvailableDevices(state, 'videoInput');
|
return !hasAvailableDevices(state, 'videoInput');
|
||||||
|
|
||||||
return isPrejoinPageVisible(state)
|
|
||||||
? devicesMissing || isPrejoinVideoDisabled(state)
|
|
||||||
: devicesMissing;
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue