diff --git a/app/src/RoomClient.js b/app/src/RoomClient.js index 6aed99c..0a1b882 100644 --- a/app/src/RoomClient.js +++ b/app/src/RoomClient.js @@ -129,21 +129,9 @@ export default class RoomClient // Map of webcam MediaDeviceInfos indexed by deviceId. // @type {Map} - this._webcams = new Map(); + this._webcams = {}; - this._audioDevices = new Map(); - - // Local Webcam. Object with: - // - {MediaDeviceInfo} [device] - // - {String} [resolution] - 'qvga' / 'vga' / 'hd'. - this._webcam = { - device : null, - resolution : 'hd' - }; - - this._audioDevice = { - device : null - }; + this._audioDevices = {}; this._screenSharing = ScreenShare.create(device); @@ -691,7 +679,7 @@ export default class RoomClient logger.debug('enableWebcam()'); // Store in cookie. - cookiesManager.setDevices({ webcamEnabled: true }); + cookiesManager.setVideoEnabled({ webcamEnabled: true }); store.dispatch(stateActions.setWebcamInProgress(true)); @@ -730,7 +718,7 @@ export default class RoomClient logger.debug('disableWebcam()'); // Store in cookie. - cookiesManager.setDevices({ webcamEnabled: false }); + cookiesManager.setVideoEnabled({ webcamEnabled: false }); store.dispatch(stateActions.setWebcamInProgress(true)); @@ -755,17 +743,15 @@ export default class RoomClient try { - this._audioDevice.device = this._audioDevices.get(deviceId); - - logger.debug( - 'changeAudioDevice() | new selected webcam [device:%o]', - this._audioDevice.device); - - const { device } = this._audioDevice; + const device = this._audioDevices[deviceId]; if (!device) throw new Error('no audio devices'); + logger.debug( + 'changeAudioDevice() | new selected webcam [device:%o]', + device); + logger.debug('changeAudioDevice() | calling getUserMedia()'); const stream = await navigator.mediaDevices.getUserMedia( @@ -813,6 +799,8 @@ export default class RoomClient store.dispatch( stateActions.setProducerTrack(this._micProducer.id, newTrack)); + store.dispatch(stateActions.setSelectedAudioDevice(deviceId)); + cookiesManager.setAudioDevice({ audioDeviceId: deviceId }); await this._updateAudioDevices(); @@ -835,19 +823,14 @@ export default class RoomClient try { - this._webcam.device = this._webcams.get(deviceId); - - logger.debug( - 'changeWebcam() | new selected webcam [device:%o]', - this._webcam.device); - - // Reset video resolution to HD. - this._webcam.resolution = 'hd'; - - const { device } = this._webcam; + const device = this._webcams[deviceId]; if (!device) throw new Error('no webcam devices'); + + logger.debug( + 'changeWebcam() | new selected webcam [device:%o]', + device); logger.debug('changeWebcam() | calling getUserMedia()'); @@ -869,6 +852,8 @@ export default class RoomClient store.dispatch( stateActions.setProducerTrack(this._webcamProducer.id, newTrack)); + store.dispatch(stateActions.setSelectedWebcamDevice(deviceId)); + cookiesManager.setVideoDevice({ videoDeviceId: deviceId }); await this._updateWebcams(); @@ -1333,7 +1318,7 @@ export default class RoomClient // Add our webcam (unless the cookie says no). if (this._room.canSend('video')) { - const devicesCookie = cookiesManager.getDevices(); + const devicesCookie = cookiesManager.getVideoEnabled(); if (!devicesCookie || devicesCookie.webcamEnabled) await this.enableWebcam(); @@ -1422,9 +1407,26 @@ export default class RoomClient try { + const deviceId = await this._getAudioDeviceId(); + + const device = this._audioDevices[deviceId]; + + if (!device) + throw new Error('no audio devices'); + + logger.debug( + '_setMicProducer() | new selected audio device [device:%o]', + device); + logger.debug('_setMicProducer() | calling getUserMedia()'); - const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); + const stream = await navigator.mediaDevices.getUserMedia( + { + audio : { + deviceId : { exact: deviceId } + } + } + ); const track = stream.getAudioTracks()[0]; @@ -1448,7 +1450,9 @@ export default class RoomClient codec : producer.rtpParameters.codecs[0].name })); - logger.debug('_setMicProducer() | calling _updateAudioDevices()'); + store.dispatch(stateActions.setSelectedAudioDevice(deviceId)); + + cookiesManager.setAudioDevice({ audioDeviceId: deviceId }); await this._updateAudioDevices(); @@ -1662,12 +1666,24 @@ export default class RoomClient try { + const deviceId = await this._getWebcamDeviceId(); + + const device = this._webcams[deviceId]; + + if (!device) + throw new Error('no webcam devices'); + + logger.debug( + '_setWebcamProducer() | new selected webcam [device:%o]', + device); + logger.debug('_setWebcamProducer() | calling getUserMedia()'); const stream = await navigator.mediaDevices.getUserMedia( { video : { + deviceId : { exact: deviceId }, ...VIDEO_CONSTRAINS } }); @@ -1695,7 +1711,10 @@ export default class RoomClient codec : producer.rtpParameters.codecs[0].name })); - logger.debug('_setWebcamProducer() | calling _updateWebcams()'); + store.dispatch(stateActions.setSelectedWebcamDevice(deviceId)); + + cookiesManager.setVideoDevice({ videoDeviceId: deviceId }); + await this._updateWebcams(); producer.on('close', (originator) => @@ -1753,7 +1772,7 @@ export default class RoomClient logger.debug('_updateAudioDevices()'); // Reset the list. - this._audioDevices = new Map(); + this._audioDevices = {}; try { @@ -1766,28 +1785,11 @@ export default class RoomClient if (device.kind !== 'audioinput') continue; - device.value = device.deviceId; - - this._audioDevices.set(device.deviceId, device); + this._audioDevices[device.deviceId] = device; } - const array = Array.from(this._audioDevices.values()); - const len = array.length; - const currentAudioDeviceId = - this._audioDevice.device ? this._audioDevice.device.deviceId : undefined; - - logger.debug('_updateAudioDevices() [audiodevices:%o]', array); - - if (len === 0) - this._audioDevice.device = null; - else if (!this._audioDevices.has(currentAudioDeviceId)) - this._audioDevice.device = array[0]; - store.dispatch( - stateActions.setCanChangeAudioDevice(len >= 2)); - if (len >= 1) - store.dispatch( - stateActions.setAudioDevices(this._audioDevices)); + stateActions.setAudioDevices(this._audioDevices)); } catch (error) { @@ -1800,7 +1802,7 @@ export default class RoomClient logger.debug('_updateWebcams()'); // Reset the list. - this._webcams = new Map(); + this._webcams = {}; try { @@ -1813,26 +1815,11 @@ export default class RoomClient if (device.kind !== 'videoinput') continue; - device.value = device.deviceId; - - this._webcams.set(device.deviceId, device); + this._webcams[device.deviceId] = device; } - const array = Array.from(this._webcams.values()); - const len = array.length; - const currentWebcamId = - this._webcam.device ? this._webcam.device.deviceId : undefined; - - logger.debug('_updateWebcams() [webcams:%o]', array); - - if (len === 0) - this._webcam.device = null; - else if (!this._webcams.has(currentWebcamId)) - this._webcam.device = array[0]; - - if (len >= 1) - store.dispatch( - stateActions.setWebcamDevices(this._webcams)); + store.dispatch( + stateActions.setWebcamDevices(this._webcams)); } catch (error) { @@ -1840,6 +1827,72 @@ export default class RoomClient } } + async _getAudioDeviceId() + { + logger.debug('_getAudioDeviceId()'); + + try + { + logger.debug('_getAudioDeviceId() | calling _updateWebcams()'); + + await this._updateAudioDevices(); + + const devicesCookie = cookiesManager.getAudioDevice(); + + if ( + devicesCookie && + devicesCookie.audioDeviceId && + this._audioDevices[devicesCookie.audioDeviceId] + ) + { + return this._audioDevices[devicesCookie.audioDeviceId].deviceId; + } + else + { + const audioDevices = Object.values(this._audioDevices); + + return audioDevices[0] ? audioDevices[0].deviceId : null; + } + } + catch (error) + { + logger.error('_getAudioDeviceId() failed:%o', error); + } + } + + async _getWebcamDeviceId() + { + logger.debug('_getWebcamDeviceId()'); + + try + { + logger.debug('_getWebcamDeviceId() | calling _updateWebcams()'); + + await this._updateWebcams(); + + const devicesCookie = cookiesManager.getVideoDevice(); + + if ( + devicesCookie && + devicesCookie.videoDeviceId && + this._webcams[devicesCookie.videoDeviceId] + ) + { + return this._webcams[devicesCookie.videoDeviceId].deviceId; + } + else + { + const webcams = Object.values(this._webcams); + + return webcams[0] ? webcams[0].deviceId : null; + } + } + catch (error) + { + logger.error('_getWebcamDeviceId() failed:%o', error); + } + } + _handlePeer(peer, { notify = true } = {}) { const displayName = peer.appData.displayName; diff --git a/app/src/actions/stateActions.js b/app/src/actions/stateActions.js index 968e949..a9614ca 100644 --- a/app/src/actions/stateActions.js +++ b/app/src/actions/stateActions.js @@ -81,14 +81,6 @@ export const setScreenCapabilities = ({ canShareScreen, needExtension }) => }; }; -export const setCanChangeAudioDevice = (flag) => -{ - return { - type : 'SET_CAN_CHANGE_AUDIO_DEVICE', - payload : flag - }; -}; - export const setAudioDevices = (devices) => { return { @@ -105,6 +97,22 @@ export const setWebcamDevices = (devices) => }; }; +export const setSelectedAudioDevice = (deviceId) => +{ + return { + type : 'CHANGE_AUDIO_DEVICE', + payload : { deviceId } + }; +}; + +export const setSelectedWebcamDevice = (deviceId) => +{ + return { + type : 'CHANGE_WEBCAM', + payload : { deviceId } + }; +}; + export const setFileSharingSupported = (supported) => { return { diff --git a/app/src/components/Settings/Settings.js b/app/src/components/Settings/Settings.js index cdccb43..fc0e9e1 100644 --- a/app/src/components/Settings/Settings.js +++ b/app/src/components/Settings/Settings.js @@ -72,14 +72,14 @@ const Settings = ({ let webcams; if (me.webcamDevices) - webcams = Array.from(me.webcamDevices.values()); + webcams = Object.values(me.webcamDevices); else webcams = []; let audioDevices; if (me.audioDevices) - audioDevices = Array.from(me.audioDevices.values()); + audioDevices = Object.values(me.audioDevices); else audioDevices = []; @@ -106,9 +106,8 @@ const Settings = ({ name='Camera' autoWidth className={classes.selectEmpty} - // disabled={!me.canChangeWebcam} + disabled={webcams.length === 0} > - { webcams.map((webcam, index) => { return ( @@ -117,7 +116,11 @@ const Settings = ({ })} - Select camera device + { webcams.length > 0 ? + 'Select video device' + : + 'Unable to select video device' + } @@ -134,9 +137,8 @@ const Settings = ({ name='Audio device' autoWidth className={classes.selectEmpty} - disabled={!me.canChangeAudioDevice} + disabled={audioDevices.length === 0} > - { audioDevices.map((audio, index) => { return ( @@ -145,7 +147,7 @@ const Settings = ({ })} - { me.canChangeAudioDevice ? + { audioDevices.length > 0 ? 'Select audio device' : 'Unable to select audio device' diff --git a/app/src/cookiesManager.js b/app/src/cookiesManager.js index 18f31cd..18659dd 100644 --- a/app/src/cookiesManager.js +++ b/app/src/cookiesManager.js @@ -1,7 +1,10 @@ import jsCookie from 'js-cookie'; const USER_COOKIE = 'multiparty-meeting.user'; -const DEVICES_COOKIE = 'multiparty-meeting.devices'; +const VIDEO_COOKIE = 'multiparty-meeting.videoEnabled'; + +const AUDIO_DEVICE = 'multiparty-meeting.audioDevice'; +const VIDEO_DEVICE = 'multiparty-meeting.videoDevice'; export function getUser() { @@ -13,22 +16,32 @@ export function setUser({ displayName }) jsCookie.set(USER_COOKIE, { displayName }); } -export function getDevices() +export function getVideoEnabled() { - return jsCookie.getJSON(DEVICES_COOKIE); + return jsCookie.getJSON(VIDEO_COOKIE); } -export function setDevices({ webcamEnabled }) +export function setVideoEnabled({ webcamEnabled }) { - jsCookie.set(DEVICES_COOKIE, { webcamEnabled }); + jsCookie.set(VIDEO_COOKIE, { webcamEnabled }); +} + +export function getAudioDevice() +{ + return jsCookie.getJSON(AUDIO_DEVICE); } export function setAudioDevice({ audioDeviceId }) { - jsCookie.set(DEVICES_COOKIE, { audioDeviceId }); + jsCookie.set(AUDIO_DEVICE, { audioDeviceId }); +} + +export function getVideoDevice() +{ + return jsCookie.getJSON(VIDEO_DEVICE); } export function setVideoDevice({ videoDeviceId }) { - jsCookie.set(DEVICES_COOKIE, { videoDeviceId }); + jsCookie.set(VIDEO_DEVICE, { videoDeviceId }); } diff --git a/app/src/reducers/me.js b/app/src/reducers/me.js index 973083a..5647f7b 100644 --- a/app/src/reducers/me.js +++ b/app/src/reducers/me.js @@ -8,9 +8,7 @@ const initialState = canSendWebcam : false, canShareScreen : false, needExtension : false, - canChangeAudioDevice : false, audioDevices : null, - canChangeWebcam : false, webcamDevices : null, webcamInProgress : false, audioInProgress : false, @@ -81,13 +79,6 @@ const me = (state = initialState, action) => return { ...state, canShareScreen, needExtension }; } - case 'SET_CAN_CHANGE_AUDIO_DEVICE': - { - const canChangeAudioDevice = action.payload; - - return { ...state, canChangeAudioDevice }; - } - case 'SET_AUDIO_DEVICES': { const { devices } = action.payload; @@ -95,13 +86,6 @@ const me = (state = initialState, action) => return { ...state, audioDevices: devices }; } - case 'SET_CAN_CHANGE_WEBCAM': - { - const canChangeWebcam = action.payload; - - return { ...state, canChangeWebcam }; - } - case 'SET_WEBCAM_DEVICES': { const { devices } = action.payload;