|
@@ -79,7 +79,9 @@ function _conferenceJoined({ dispatch, getState }, next, action) {
|
79
|
79
|
|
80
|
80
|
/**
|
81
|
81
|
* Finds a new device by comparing new and old array of devices and dispatches
|
82
|
|
- * notification with the new device.
|
|
82
|
+ * notification with the new device. For new devices with same groupId only one
|
|
83
|
+ * notification will be shown, this is so to avoid showing multiple notifications
|
|
84
|
+ * for audio input and audio output devices.
|
83
|
85
|
*
|
84
|
86
|
* @param {Store} store - The redux store in which the specified {@code action}
|
85
|
87
|
* is being dispatched.
|
|
@@ -97,7 +99,25 @@ function _checkAndNotifyForNewDevice(store, newDevices, oldDevices) {
|
97
|
99
|
nDevice => !oldDevices.find(
|
98
|
100
|
device => device.deviceId === nDevice.deviceId));
|
99
|
101
|
|
100
|
|
- onlyNewDevices.forEach(newDevice => {
|
|
102
|
+ // we group devices by groupID which normally is the grouping by physical device
|
|
103
|
+ // plugging in headset we provide normally two device, one input and one output
|
|
104
|
+ // and we want to show only one notification for this physical audio device
|
|
105
|
+ const devicesGroupBy = onlyNewDevices.reduce((accumulated, value) => {
|
|
106
|
+ accumulated[value.groupId] = accumulated[value.groupId] || [];
|
|
107
|
+ accumulated[value.groupId].push(value);
|
|
108
|
+
|
|
109
|
+ return accumulated;
|
|
110
|
+ }, {});
|
|
111
|
+
|
|
112
|
+ Object.values(devicesGroupBy).forEach(devicesArray => {
|
|
113
|
+
|
|
114
|
+ if (devicesArray.length < 1) {
|
|
115
|
+ return;
|
|
116
|
+ }
|
|
117
|
+
|
|
118
|
+ // let's get the first device as a reference, we will use it for
|
|
119
|
+ // label and type
|
|
120
|
+ const newDevice = devicesArray[0];
|
101
|
121
|
|
102
|
122
|
// we want to strip any device details that are not very
|
103
|
123
|
// user friendly, like usb ids put in brackets at the end
|
|
@@ -115,12 +135,9 @@ function _checkAndNotifyForNewDevice(store, newDevices, oldDevices) {
|
115
|
135
|
titleKey = 'notify.newDeviceCameraTitle';
|
116
|
136
|
break;
|
117
|
137
|
}
|
118
|
|
- case 'audioinput': {
|
119
|
|
- titleKey = 'notify.newDeviceMicTitle';
|
120
|
|
- break;
|
121
|
|
- }
|
|
138
|
+ case 'audioinput' :
|
122
|
139
|
case 'audiooutput': {
|
123
|
|
- titleKey = 'notify.newDeviceCameraTitle';
|
|
140
|
+ titleKey = 'notify.newDeviceAudioTitle';
|
124
|
141
|
break;
|
125
|
142
|
}
|
126
|
143
|
}
|
|
@@ -129,7 +146,7 @@ function _checkAndNotifyForNewDevice(store, newDevices, oldDevices) {
|
129
|
146
|
description,
|
130
|
147
|
titleKey,
|
131
|
148
|
customActionNameKey: 'notify.newDeviceAction',
|
132
|
|
- customActionHandler: _useDevice.bind(undefined, store, newDevice)
|
|
149
|
+ customActionHandler: _useDevice.bind(undefined, store, devicesArray)
|
133
|
150
|
}));
|
134
|
151
|
});
|
135
|
152
|
}
|
|
@@ -139,47 +156,49 @@ function _checkAndNotifyForNewDevice(store, newDevices, oldDevices) {
|
139
|
156
|
*
|
140
|
157
|
* @param {Store} store - The redux store in which the specified {@code action}
|
141
|
158
|
* is being dispatched.
|
142
|
|
- * @param {MediaDeviceInfo} device - The device to save.
|
|
159
|
+ * @param {Array<MediaDeviceInfo|InputDeviceInfo>} devices - The devices to save.
|
143
|
160
|
* @returns {boolean} - Returns true in order notifications to be dismissed.
|
144
|
161
|
* @private
|
145
|
162
|
*/
|
146
|
|
-function _useDevice({ dispatch }, device) {
|
147
|
|
- switch (device.kind) {
|
148
|
|
- case 'videoinput': {
|
149
|
|
- dispatch(updateSettings({
|
150
|
|
- userSelectedCameraDeviceId: device.deviceId,
|
151
|
|
- userSelectedCameraDeviceLabel: device.label
|
152
|
|
- }));
|
|
163
|
+function _useDevice({ dispatch }, devices) {
|
|
164
|
+ devices.forEach(device => {
|
|
165
|
+ switch (device.kind) {
|
|
166
|
+ case 'videoinput': {
|
|
167
|
+ dispatch(updateSettings({
|
|
168
|
+ userSelectedCameraDeviceId: device.deviceId,
|
|
169
|
+ userSelectedCameraDeviceLabel: device.label
|
|
170
|
+ }));
|
153
|
171
|
|
154
|
|
- dispatch(setVideoInputDevice(device.deviceId));
|
155
|
|
- break;
|
156
|
|
- }
|
157
|
|
- case 'audioinput': {
|
158
|
|
- dispatch(updateSettings({
|
159
|
|
- userSelectedMicDeviceId: device.deviceId,
|
160
|
|
- userSelectedMicDeviceLabel: device.label
|
161
|
|
- }));
|
|
172
|
+ dispatch(setVideoInputDevice(device.deviceId));
|
|
173
|
+ break;
|
|
174
|
+ }
|
|
175
|
+ case 'audioinput': {
|
|
176
|
+ dispatch(updateSettings({
|
|
177
|
+ userSelectedMicDeviceId: device.deviceId,
|
|
178
|
+ userSelectedMicDeviceLabel: device.label
|
|
179
|
+ }));
|
162
|
180
|
|
163
|
|
- dispatch(setAudioInputDevice(device.deviceId));
|
164
|
|
- break;
|
165
|
|
- }
|
166
|
|
- case 'audiooutput': {
|
167
|
|
- setAudioOutputDeviceId(
|
168
|
|
- device.deviceId,
|
169
|
|
- dispatch,
|
170
|
|
- true,
|
171
|
|
- device.label)
|
172
|
|
- .then(() => logger.log('changed audio output device'))
|
173
|
|
- .catch(err => {
|
174
|
|
- logger.warn(
|
175
|
|
- 'Failed to change audio output device.',
|
176
|
|
- 'Default or previously set audio output device will',
|
177
|
|
- ' be used instead.',
|
178
|
|
- err);
|
179
|
|
- });
|
180
|
|
- break;
|
181
|
|
- }
|
182
|
|
- }
|
|
181
|
+ dispatch(setAudioInputDevice(device.deviceId));
|
|
182
|
+ break;
|
|
183
|
+ }
|
|
184
|
+ case 'audiooutput': {
|
|
185
|
+ setAudioOutputDeviceId(
|
|
186
|
+ device.deviceId,
|
|
187
|
+ dispatch,
|
|
188
|
+ true,
|
|
189
|
+ device.label)
|
|
190
|
+ .then(() => logger.log('changed audio output device'))
|
|
191
|
+ .catch(err => {
|
|
192
|
+ logger.warn(
|
|
193
|
+ 'Failed to change audio output device.',
|
|
194
|
+ 'Default or previously set audio output device will',
|
|
195
|
+ ' be used instead.',
|
|
196
|
+ err);
|
|
197
|
+ });
|
|
198
|
+ break;
|
|
199
|
+ }
|
|
200
|
+ }
|
|
201
|
+ });
|
183
|
202
|
|
184
|
203
|
return true;
|
185
|
204
|
}
|