Merge branch 'feat-device-management' into develop

master
Håvar Aambø Fosstveit 2019-04-05 13:34:23 +02:00
commit 048cd8758b
5 changed files with 175 additions and 115 deletions

View File

@ -129,21 +129,9 @@ export default class RoomClient
// Map of webcam MediaDeviceInfos indexed by deviceId. // Map of webcam MediaDeviceInfos indexed by deviceId.
// @type {Map<String, MediaDeviceInfos>} // @type {Map<String, MediaDeviceInfos>}
this._webcams = new Map(); this._webcams = {};
this._audioDevices = new Map(); this._audioDevices = {};
// Local Webcam. Object with:
// - {MediaDeviceInfo} [device]
// - {String} [resolution] - 'qvga' / 'vga' / 'hd'.
this._webcam = {
device : null,
resolution : 'hd'
};
this._audioDevice = {
device : null
};
this._screenSharing = ScreenShare.create(device); this._screenSharing = ScreenShare.create(device);
@ -691,7 +679,7 @@ export default class RoomClient
logger.debug('enableWebcam()'); logger.debug('enableWebcam()');
// Store in cookie. // Store in cookie.
cookiesManager.setDevices({ webcamEnabled: true }); cookiesManager.setVideoEnabled({ webcamEnabled: true });
store.dispatch(stateActions.setWebcamInProgress(true)); store.dispatch(stateActions.setWebcamInProgress(true));
@ -730,7 +718,7 @@ export default class RoomClient
logger.debug('disableWebcam()'); logger.debug('disableWebcam()');
// Store in cookie. // Store in cookie.
cookiesManager.setDevices({ webcamEnabled: false }); cookiesManager.setVideoEnabled({ webcamEnabled: false });
store.dispatch(stateActions.setWebcamInProgress(true)); store.dispatch(stateActions.setWebcamInProgress(true));
@ -755,17 +743,15 @@ export default class RoomClient
try try
{ {
this._audioDevice.device = this._audioDevices.get(deviceId); const device = this._audioDevices[deviceId];
logger.debug(
'changeAudioDevice() | new selected webcam [device:%o]',
this._audioDevice.device);
const { device } = this._audioDevice;
if (!device) if (!device)
throw new Error('no audio devices'); throw new Error('no audio devices');
logger.debug(
'changeAudioDevice() | new selected webcam [device:%o]',
device);
logger.debug('changeAudioDevice() | calling getUserMedia()'); logger.debug('changeAudioDevice() | calling getUserMedia()');
const stream = await navigator.mediaDevices.getUserMedia( const stream = await navigator.mediaDevices.getUserMedia(
@ -813,6 +799,8 @@ export default class RoomClient
store.dispatch( store.dispatch(
stateActions.setProducerTrack(this._micProducer.id, newTrack)); stateActions.setProducerTrack(this._micProducer.id, newTrack));
store.dispatch(stateActions.setSelectedAudioDevice(deviceId));
cookiesManager.setAudioDevice({ audioDeviceId: deviceId }); cookiesManager.setAudioDevice({ audioDeviceId: deviceId });
await this._updateAudioDevices(); await this._updateAudioDevices();
@ -835,19 +823,14 @@ export default class RoomClient
try try
{ {
this._webcam.device = this._webcams.get(deviceId); const device = this._webcams[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;
if (!device) if (!device)
throw new Error('no webcam devices'); throw new Error('no webcam devices');
logger.debug(
'changeWebcam() | new selected webcam [device:%o]',
device);
logger.debug('changeWebcam() | calling getUserMedia()'); logger.debug('changeWebcam() | calling getUserMedia()');
@ -869,6 +852,8 @@ export default class RoomClient
store.dispatch( store.dispatch(
stateActions.setProducerTrack(this._webcamProducer.id, newTrack)); stateActions.setProducerTrack(this._webcamProducer.id, newTrack));
store.dispatch(stateActions.setSelectedWebcamDevice(deviceId));
cookiesManager.setVideoDevice({ videoDeviceId: deviceId }); cookiesManager.setVideoDevice({ videoDeviceId: deviceId });
await this._updateWebcams(); await this._updateWebcams();
@ -1333,7 +1318,7 @@ export default class RoomClient
// Add our webcam (unless the cookie says no). // Add our webcam (unless the cookie says no).
if (this._room.canSend('video')) if (this._room.canSend('video'))
{ {
const devicesCookie = cookiesManager.getDevices(); const devicesCookie = cookiesManager.getVideoEnabled();
if (!devicesCookie || devicesCookie.webcamEnabled) if (!devicesCookie || devicesCookie.webcamEnabled)
await this.enableWebcam(); await this.enableWebcam();
@ -1422,9 +1407,26 @@ export default class RoomClient
try 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()'); 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]; const track = stream.getAudioTracks()[0];
@ -1448,7 +1450,9 @@ export default class RoomClient
codec : producer.rtpParameters.codecs[0].name codec : producer.rtpParameters.codecs[0].name
})); }));
logger.debug('_setMicProducer() | calling _updateAudioDevices()'); store.dispatch(stateActions.setSelectedAudioDevice(deviceId));
cookiesManager.setAudioDevice({ audioDeviceId: deviceId });
await this._updateAudioDevices(); await this._updateAudioDevices();
@ -1662,12 +1666,24 @@ export default class RoomClient
try 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()'); logger.debug('_setWebcamProducer() | calling getUserMedia()');
const stream = await navigator.mediaDevices.getUserMedia( const stream = await navigator.mediaDevices.getUserMedia(
{ {
video : video :
{ {
deviceId : { exact: deviceId },
...VIDEO_CONSTRAINS ...VIDEO_CONSTRAINS
} }
}); });
@ -1695,7 +1711,10 @@ export default class RoomClient
codec : producer.rtpParameters.codecs[0].name codec : producer.rtpParameters.codecs[0].name
})); }));
logger.debug('_setWebcamProducer() | calling _updateWebcams()'); store.dispatch(stateActions.setSelectedWebcamDevice(deviceId));
cookiesManager.setVideoDevice({ videoDeviceId: deviceId });
await this._updateWebcams(); await this._updateWebcams();
producer.on('close', (originator) => producer.on('close', (originator) =>
@ -1753,7 +1772,7 @@ export default class RoomClient
logger.debug('_updateAudioDevices()'); logger.debug('_updateAudioDevices()');
// Reset the list. // Reset the list.
this._audioDevices = new Map(); this._audioDevices = {};
try try
{ {
@ -1766,28 +1785,11 @@ export default class RoomClient
if (device.kind !== 'audioinput') if (device.kind !== 'audioinput')
continue; continue;
device.value = device.deviceId; this._audioDevices[device.deviceId] = device;
this._audioDevices.set(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( store.dispatch(
stateActions.setCanChangeAudioDevice(len >= 2)); stateActions.setAudioDevices(this._audioDevices));
if (len >= 1)
store.dispatch(
stateActions.setAudioDevices(this._audioDevices));
} }
catch (error) catch (error)
{ {
@ -1800,7 +1802,7 @@ export default class RoomClient
logger.debug('_updateWebcams()'); logger.debug('_updateWebcams()');
// Reset the list. // Reset the list.
this._webcams = new Map(); this._webcams = {};
try try
{ {
@ -1813,26 +1815,11 @@ export default class RoomClient
if (device.kind !== 'videoinput') if (device.kind !== 'videoinput')
continue; continue;
device.value = device.deviceId; this._webcams[device.deviceId] = device;
this._webcams.set(device.deviceId, device);
} }
const array = Array.from(this._webcams.values()); store.dispatch(
const len = array.length; stateActions.setWebcamDevices(this._webcams));
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));
} }
catch (error) 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 } = {}) _handlePeer(peer, { notify = true } = {})
{ {
const displayName = peer.appData.displayName; const displayName = peer.appData.displayName;

View File

@ -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) => export const setAudioDevices = (devices) =>
{ {
return { 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) => export const setFileSharingSupported = (supported) =>
{ {
return { return {

View File

@ -72,14 +72,14 @@ const Settings = ({
let webcams; let webcams;
if (me.webcamDevices) if (me.webcamDevices)
webcams = Array.from(me.webcamDevices.values()); webcams = Object.values(me.webcamDevices);
else else
webcams = []; webcams = [];
let audioDevices; let audioDevices;
if (me.audioDevices) if (me.audioDevices)
audioDevices = Array.from(me.audioDevices.values()); audioDevices = Object.values(me.audioDevices);
else else
audioDevices = []; audioDevices = [];
@ -106,9 +106,8 @@ const Settings = ({
name='Camera' name='Camera'
autoWidth autoWidth
className={classes.selectEmpty} className={classes.selectEmpty}
// disabled={!me.canChangeWebcam} disabled={webcams.length === 0}
> >
<MenuItem value='' />
{ webcams.map((webcam, index) => { webcams.map((webcam, index) =>
{ {
return ( return (
@ -117,7 +116,11 @@ const Settings = ({
})} })}
</Select> </Select>
<FormHelperText> <FormHelperText>
Select camera device { webcams.length > 0 ?
'Select video device'
:
'Unable to select video device'
}
</FormHelperText> </FormHelperText>
</FormControl> </FormControl>
</form> </form>
@ -134,9 +137,8 @@ const Settings = ({
name='Audio device' name='Audio device'
autoWidth autoWidth
className={classes.selectEmpty} className={classes.selectEmpty}
disabled={!me.canChangeAudioDevice} disabled={audioDevices.length === 0}
> >
<MenuItem value='' />
{ audioDevices.map((audio, index) => { audioDevices.map((audio, index) =>
{ {
return ( return (
@ -145,7 +147,7 @@ const Settings = ({
})} })}
</Select> </Select>
<FormHelperText> <FormHelperText>
{ me.canChangeAudioDevice ? { audioDevices.length > 0 ?
'Select audio device' 'Select audio device'
: :
'Unable to select audio device' 'Unable to select audio device'

View File

@ -1,7 +1,10 @@
import jsCookie from 'js-cookie'; import jsCookie from 'js-cookie';
const USER_COOKIE = 'multiparty-meeting.user'; 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() export function getUser()
{ {
@ -13,22 +16,32 @@ export function setUser({ displayName })
jsCookie.set(USER_COOKIE, { 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 }) 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 }) export function setVideoDevice({ videoDeviceId })
{ {
jsCookie.set(DEVICES_COOKIE, { videoDeviceId }); jsCookie.set(VIDEO_DEVICE, { videoDeviceId });
} }

View File

@ -8,9 +8,7 @@ const initialState =
canSendWebcam : false, canSendWebcam : false,
canShareScreen : false, canShareScreen : false,
needExtension : false, needExtension : false,
canChangeAudioDevice : false,
audioDevices : null, audioDevices : null,
canChangeWebcam : false,
webcamDevices : null, webcamDevices : null,
webcamInProgress : false, webcamInProgress : false,
audioInProgress : false, audioInProgress : false,
@ -81,13 +79,6 @@ const me = (state = initialState, action) =>
return { ...state, canShareScreen, needExtension }; return { ...state, canShareScreen, needExtension };
} }
case 'SET_CAN_CHANGE_AUDIO_DEVICE':
{
const canChangeAudioDevice = action.payload;
return { ...state, canChangeAudioDevice };
}
case 'SET_AUDIO_DEVICES': case 'SET_AUDIO_DEVICES':
{ {
const { devices } = action.payload; const { devices } = action.payload;
@ -95,13 +86,6 @@ const me = (state = initialState, action) =>
return { ...state, audioDevices: devices }; return { ...state, audioDevices: devices };
} }
case 'SET_CAN_CHANGE_WEBCAM':
{
const canChangeWebcam = action.payload;
return { ...state, canChangeWebcam };
}
case 'SET_WEBCAM_DEVICES': case 'SET_WEBCAM_DEVICES':
{ {
const { devices } = action.payload; const { devices } = action.payload;