Added support for setting audio input device, not working on linux at the moment. Updated webcam selection.
parent
7e1b391fe1
commit
fcb15e706d
|
|
@ -79,7 +79,9 @@ export default class RoomClient
|
|||
|
||||
// Map of webcam MediaDeviceInfos indexed by deviceId.
|
||||
// @type {Map<String, MediaDeviceInfos>}
|
||||
this._webcams = new Map();
|
||||
this._webcams = {};
|
||||
|
||||
this._audioDevices = {};
|
||||
|
||||
// Local Webcam. Object with:
|
||||
// - {MediaDeviceInfo} [device]
|
||||
|
|
@ -89,6 +91,10 @@ export default class RoomClient
|
|||
resolution : 'hd'
|
||||
};
|
||||
|
||||
this._audioDevice = {
|
||||
device : null
|
||||
};
|
||||
|
||||
this._screenSharing = ScreenShare.create();
|
||||
|
||||
this._screenSharingProducer = null;
|
||||
|
|
@ -366,6 +372,72 @@ export default class RoomClient
|
|||
});
|
||||
}
|
||||
|
||||
changeAudioDevice(deviceId)
|
||||
{
|
||||
logger.debug('changeAudioDevice() [deviceId: %s]', deviceId);
|
||||
|
||||
this._dispatch(
|
||||
stateActions.setAudioInProgress(true));
|
||||
|
||||
return Promise.resolve()
|
||||
.then(() =>
|
||||
{
|
||||
this._audioDevice.device = this._audioDevices[deviceId];
|
||||
|
||||
logger.debug(
|
||||
'changeAudioDevice() | new selected webcam [device:%o]',
|
||||
this._audioDevice.device);
|
||||
})
|
||||
.then(() =>
|
||||
{
|
||||
const { device } = this._audioDevice;
|
||||
|
||||
if (!device)
|
||||
throw new Error('no audio devices');
|
||||
|
||||
logger.debug('changeAudioDevice() | calling getUserMedia()');
|
||||
|
||||
return navigator.mediaDevices.getUserMedia(
|
||||
{
|
||||
audio :
|
||||
{
|
||||
deviceId : { exact: device.deviceId }
|
||||
}
|
||||
});
|
||||
})
|
||||
.then((stream) =>
|
||||
{
|
||||
const track = stream.getAudioTracks()[0];
|
||||
|
||||
return this._micProducer.replaceTrack(track)
|
||||
.then((newTrack) =>
|
||||
{
|
||||
track.stop();
|
||||
|
||||
return newTrack;
|
||||
});
|
||||
})
|
||||
.then((newTrack) =>
|
||||
{
|
||||
this._dispatch(
|
||||
stateActions.setProducerTrack(this._micProducer.id, newTrack));
|
||||
|
||||
return this._updateAudioDevices();
|
||||
})
|
||||
.then(() =>
|
||||
{
|
||||
this._dispatch(
|
||||
stateActions.setAudioInProgress(false));
|
||||
})
|
||||
.catch((error) =>
|
||||
{
|
||||
logger.error('changeAudioDevice() failed: %o', error);
|
||||
|
||||
this._dispatch(
|
||||
stateActions.setAudioInProgress(false));
|
||||
});
|
||||
}
|
||||
|
||||
changeWebcam(deviceId)
|
||||
{
|
||||
logger.debug('changeWebcam() [deviceId: %s]', deviceId);
|
||||
|
|
@ -376,20 +448,7 @@ export default class RoomClient
|
|||
return Promise.resolve()
|
||||
.then(() =>
|
||||
{
|
||||
logger.debug('changeWebcam() | calling enumerateDevices()');
|
||||
|
||||
return navigator.mediaDevices.enumerateDevices();
|
||||
})
|
||||
.then((devices) =>
|
||||
{
|
||||
for (const device of devices)
|
||||
{
|
||||
if (device.kind !== 'videoinput')
|
||||
continue;
|
||||
|
||||
if (device.deviceId == deviceId)
|
||||
this._webcam.device = device;
|
||||
}
|
||||
this._webcam.device = this._webcams[deviceId];
|
||||
|
||||
logger.debug(
|
||||
'changeWebcam() | new selected webcam [device:%o]',
|
||||
|
|
@ -433,6 +492,10 @@ export default class RoomClient
|
|||
this._dispatch(
|
||||
stateActions.setProducerTrack(this._webcamProducer.id, newTrack));
|
||||
|
||||
return this._updateWebcams();
|
||||
})
|
||||
.then(() =>
|
||||
{
|
||||
this._dispatch(
|
||||
stateActions.setWebcamInProgress(false));
|
||||
})
|
||||
|
|
@ -1161,6 +1224,12 @@ export default class RoomClient
|
|||
let producer;
|
||||
|
||||
return Promise.resolve()
|
||||
.then(() =>
|
||||
{
|
||||
logger.debug('_setMicProducer() | calling _updateAudioDevices()');
|
||||
|
||||
return this._updateAudioDevices();
|
||||
})
|
||||
.then(() =>
|
||||
{
|
||||
logger.debug('_setMicProducer() | calling getUserMedia()');
|
||||
|
|
@ -1480,6 +1549,58 @@ export default class RoomClient
|
|||
});
|
||||
}
|
||||
|
||||
_updateAudioDevices()
|
||||
{
|
||||
logger.debug('_updateAudioDevices()');
|
||||
|
||||
// Reset the list.
|
||||
this._audioDevices = {};
|
||||
|
||||
return Promise.resolve()
|
||||
.then(() =>
|
||||
{
|
||||
logger.debug('_updateAudioDevices() | calling enumerateDevices()');
|
||||
|
||||
return navigator.mediaDevices.enumerateDevices();
|
||||
})
|
||||
.then((devices) =>
|
||||
{
|
||||
for (const device of devices)
|
||||
{
|
||||
if (device.kind !== 'audioinput')
|
||||
continue;
|
||||
|
||||
this._audioDevices[device.deviceId] = {
|
||||
value : device.deviceId,
|
||||
label : device.label,
|
||||
deviceId : device.deviceId
|
||||
};
|
||||
}
|
||||
})
|
||||
.then(() =>
|
||||
{
|
||||
const currentAudioDeviceId =
|
||||
this._audioDevice.device ? this._audioDevice.device.deviceId : undefined;
|
||||
|
||||
logger.debug('_updateAudioDevices() [audiodevices:%o]', this._audioDevices);
|
||||
|
||||
const len = Object.keys(this._audioDevices).length;
|
||||
|
||||
if (len === 0)
|
||||
this._audioDevice.device = null;
|
||||
else if (!this._audioDevices[currentAudioDeviceId])
|
||||
for (this._audioDevice.device in this._audioDevices)
|
||||
if (this._audioDevices.hasOwnProperty(this._audioDevice.device))
|
||||
break;
|
||||
|
||||
this._dispatch(
|
||||
stateActions.setCanChangeAudioDevice(len >= 2));
|
||||
if (len >= 1)
|
||||
this._dispatch(
|
||||
stateActions.setAudioDevices(this._audioDevices));
|
||||
});
|
||||
}
|
||||
|
||||
_updateWebcams()
|
||||
{
|
||||
logger.debug('_updateWebcams()');
|
||||
|
|
@ -1503,7 +1624,8 @@ export default class RoomClient
|
|||
|
||||
this._webcams[device.deviceId] = {
|
||||
value : device.deviceId,
|
||||
label : device.label
|
||||
label : device.label,
|
||||
deviceId : device.deviceId
|
||||
};
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -80,7 +80,9 @@ class Me extends React.Component
|
|||
{connected ?
|
||||
<div className='controls'>
|
||||
<div
|
||||
className={classnames('button', 'mic', micState)}
|
||||
className={classnames('button', 'mic', micState, {
|
||||
disabled : me.audioInProgress
|
||||
})}
|
||||
onClick={() =>
|
||||
{
|
||||
micState === 'on' ? onMuteMic() : onUnmuteMic();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { connect } from 'react-redux';
|
|||
import * as appPropTypes from './appPropTypes';
|
||||
import * as requestActions from '../redux/requestActions';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Appear } from './transitions';
|
||||
import Dropdown from 'react-dropdown';
|
||||
|
||||
class Settings extends React.Component
|
||||
|
|
@ -18,15 +19,41 @@ class Settings extends React.Component
|
|||
room,
|
||||
me,
|
||||
handleChangeWebcam,
|
||||
handleChangeAudioDevice,
|
||||
onToggleSettings
|
||||
} = this.props;
|
||||
|
||||
if (!room.showSettings)
|
||||
return null;
|
||||
|
||||
const webcams = Object.values(me.webcamDevices);
|
||||
let webcams;
|
||||
let webcamText;
|
||||
|
||||
if (me.canChangeWebcam)
|
||||
webcamText = 'Select camera';
|
||||
else
|
||||
webcamText = 'Unable to select camera';
|
||||
|
||||
if (me.webcamDevices)
|
||||
webcams = Object.values(me.webcamDevices);
|
||||
else
|
||||
webcams = [];
|
||||
|
||||
let audioDevices;
|
||||
let audioDevicesText;
|
||||
|
||||
if (me.canChangeAudioDevice)
|
||||
audioDevicesText = 'Select audio input device';
|
||||
else
|
||||
audioDevicesText = 'Unable to select audio input device';
|
||||
|
||||
if (me.audioDevices)
|
||||
audioDevices = Object.values(me.audioDevices);
|
||||
else
|
||||
audioDevices = [];
|
||||
|
||||
return (
|
||||
<Appear duration={500}>
|
||||
<div data-component='Settings'>
|
||||
<div className='dialog'>
|
||||
<div className='header'>
|
||||
|
|
@ -37,8 +64,13 @@ class Settings extends React.Component
|
|||
disabled={!me.canChangeWebcam}
|
||||
options={webcams}
|
||||
onChange={handleChangeWebcam}
|
||||
value={webcams[0]}
|
||||
placeholder='No other cameras detected'
|
||||
placeholder={webcamText}
|
||||
/>
|
||||
<Dropdown
|
||||
disabled={!me.canChangeAudioDevice}
|
||||
options={audioDevices}
|
||||
onChange={handleChangeAudioDevice}
|
||||
placeholder={audioDevicesText}
|
||||
/>
|
||||
</div>
|
||||
<div className='footer'>
|
||||
|
|
@ -51,6 +83,7 @@ class Settings extends React.Component
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Appear>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -60,7 +93,8 @@ Settings.propTypes =
|
|||
me : appPropTypes.Me.isRequired,
|
||||
room : appPropTypes.Room.isRequired,
|
||||
onToggleSettings : PropTypes.func.isRequired,
|
||||
handleChangeWebcam : PropTypes.func.isRequired
|
||||
handleChangeWebcam : PropTypes.func.isRequired,
|
||||
handleChangeAudioDevice : PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) =>
|
||||
|
|
@ -77,6 +111,10 @@ const mapDispatchToProps = (dispatch) =>
|
|||
handleChangeWebcam : (device) =>
|
||||
{
|
||||
dispatch(requestActions.changeWebcam(device.value));
|
||||
},
|
||||
handleChangeAudioDevice : (device) =>
|
||||
{
|
||||
dispatch(requestActions.changeAudioDevice(device.value));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,9 +8,12 @@ const initialState =
|
|||
canSendWebcam : false,
|
||||
canShareScreen : false,
|
||||
needExtension : false,
|
||||
canChangeAudioDevice : false,
|
||||
audioDevices : null,
|
||||
canChangeWebcam : false,
|
||||
webcamDevices : null,
|
||||
webcamInProgress : false,
|
||||
audioInProgress : false,
|
||||
screenShareInProgress : false,
|
||||
audioOnly : false,
|
||||
audioOnlyInProgress : false,
|
||||
|
|
@ -44,6 +47,20 @@ 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;
|
||||
|
||||
return { ...state, audioDevices: devices };
|
||||
}
|
||||
|
||||
case 'SET_CAN_CHANGE_WEBCAM':
|
||||
{
|
||||
const canChangeWebcam = action.payload;
|
||||
|
|
@ -53,11 +70,18 @@ const me = (state = initialState, action) =>
|
|||
|
||||
case 'SET_WEBCAM_DEVICES':
|
||||
{
|
||||
const devices = action.payload;
|
||||
const { devices } = action.payload;
|
||||
|
||||
return { ...state, webcamDevices: devices };
|
||||
}
|
||||
|
||||
case 'SET_AUDIO_IN_PROGRESS':
|
||||
{
|
||||
const { flag } = action.payload;
|
||||
|
||||
return { ...state, audioInProgress: flag };
|
||||
}
|
||||
|
||||
case 'SET_WEBCAM_IN_PROGRESS':
|
||||
{
|
||||
const { flag } = action.payload;
|
||||
|
|
|
|||
|
|
@ -65,6 +65,14 @@ export const changeWebcam = (deviceId) =>
|
|||
};
|
||||
};
|
||||
|
||||
export const changeAudioDevice = (deviceId) =>
|
||||
{
|
||||
return {
|
||||
type : 'CHANGE_AUDIO_DEVICE',
|
||||
payload : { deviceId }
|
||||
};
|
||||
};
|
||||
|
||||
export const enableAudioOnly = () =>
|
||||
{
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -90,6 +90,15 @@ export default ({ dispatch, getState }) => (next) =>
|
|||
break;
|
||||
}
|
||||
|
||||
case 'CHANGE_AUDIO_DEVICE':
|
||||
{
|
||||
const { deviceId } = action.payload;
|
||||
|
||||
client.changeAudioDevice(deviceId);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'ENABLE_AUDIO_ONLY':
|
||||
{
|
||||
client.enableAudioOnly();
|
||||
|
|
|
|||
|
|
@ -54,6 +54,22 @@ export const setScreenCapabilities = ({ canShareScreen, needExtension }) =>
|
|||
};
|
||||
};
|
||||
|
||||
export const setCanChangeAudioDevice = (flag) =>
|
||||
{
|
||||
return {
|
||||
type : 'SET_CAN_CHANGE_AUDIO_DEVICE',
|
||||
payload : flag
|
||||
};
|
||||
};
|
||||
|
||||
export const setAudioDevices = (devices) =>
|
||||
{
|
||||
return {
|
||||
type : 'SET_AUDIO_DEVICES',
|
||||
payload : { devices }
|
||||
};
|
||||
};
|
||||
|
||||
export const setCanChangeWebcam = (flag) =>
|
||||
{
|
||||
return {
|
||||
|
|
@ -66,7 +82,7 @@ export const setWebcamDevices = (devices) =>
|
|||
{
|
||||
return {
|
||||
type : 'SET_WEBCAM_DEVICES',
|
||||
payload : devices
|
||||
payload : { devices }
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -189,6 +205,14 @@ export const setProducerTrack = (producerId, track) =>
|
|||
};
|
||||
};
|
||||
|
||||
export const setAudioInProgress = (flag) =>
|
||||
{
|
||||
return {
|
||||
type : 'SET_AUDIO_IN_PROGRESS',
|
||||
payload : { flag }
|
||||
};
|
||||
};
|
||||
|
||||
export const setWebcamInProgress = (flag) =>
|
||||
{
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
z-index: 19999;
|
||||
background-color: rgba(000, 000, 000, 0.5);
|
||||
|
||||
AppearFadeIn(500ms);
|
||||
|
||||
> .dialog {
|
||||
position: absolute;
|
||||
height: 50vmin;
|
||||
|
|
@ -29,6 +31,8 @@
|
|||
> .settings {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding-top: 1vmin;
|
||||
padding-bottom: 1vmin;
|
||||
|
||||
.Dropdown-root {
|
||||
position: relative;
|
||||
|
|
|
|||
Loading…
Reference in New Issue