Quellcode durchsuchen

Added ability to switch audio output device - changes after review

dev1
Kostiantyn Tsaregradskyi vor 9 Jahren
Ursprung
Commit
eddea0a02a
5 geänderte Dateien mit 58 neuen und 67 gelöschten Zeilen
  1. 7
    12
      JitsiMeetJS.js
  2. 1
    1
      doc/example/example.js
  3. 11
    16
      modules/RTC/JitsiTrack.js
  4. 9
    14
      modules/RTC/RTC.js
  5. 30
    24
      modules/RTC/RTCUtils.js

+ 7
- 12
JitsiMeetJS.js Datei anzeigen

@@ -140,19 +140,14 @@ var LibJitsiMeet = {
140 140
         return RTC.isDeviceListAvailable();
141 141
     },
142 142
     /**
143
-     * Returns true if changing the camera / microphone device is supported and
144
-     * false if not.
143
+     * Returns true if changing the input (camera / microphone) or output
144
+     * (audio) device is supported and false if not.
145
+     * @params {string} [deviceType] - type of device to change. Default is
146
+     *      undefined or 'input', 'output' - for audio output device change.
145 147
      * @returns {boolean} true if available, false otherwise.
146 148
      */
147
-    isDeviceChangeAvailable: function () {
148
-        return RTC.isDeviceChangeAvailable();
149
-    },
150
-    /**
151
-     * Returns true if changing the audio output of media elements is supported
152
-     * and false if not.
153
-     */
154
-    isAudioOutputDeviceChangeAvailable: function () {
155
-        return RTC.isAudioOutputDeviceChangeAvailable();
149
+    isDeviceChangeAvailable: function (deviceType) {
150
+        return RTC.isDeviceChangeAvailable(deviceType);
156 151
     },
157 152
     /**
158 153
      * Returns currently used audio output device id, '' stands for default
@@ -165,7 +160,7 @@ var LibJitsiMeet = {
165 160
     /**
166 161
      * Sets current audio output device.
167 162
      * @param {string} deviceId - id of 'audiooutput' device from
168
-     *      navigator.mediaDevices.enumerateDevices()
163
+     *      navigator.mediaDevices.enumerateDevices(), '' is for default device
169 164
      * @returns {Promise} - resolves when audio output is changed, is rejected
170 165
      *      otherwise
171 166
      */

+ 1
- 1
doc/example/example.js Datei anzeigen

@@ -241,7 +241,7 @@ JitsiMeetJS.init(initOptions).then(function(){
241 241
 });
242 242
 
243 243
 
244
-if (JitsiMeetJS.isAudioOutputDeviceChangeAvailable()) {
244
+if (JitsiMeetJS.isDeviceChangeAvailable('output')) {
245 245
     JitsiMeetJS.enumerateDevices(function(devices) {
246 246
         var audioOutputDevices = devices.filter(function(d) { return d.kind === 'audiooutput'; });
247 247
 

+ 11
- 16
modules/RTC/JitsiTrack.js Datei anzeigen

@@ -313,39 +313,34 @@ JitsiTrack.prototype.getMSID = function () {
313 313
 };
314 314
 
315 315
 /**
316
- * Set new audio output device for track's DOM elements.
316
+ * Sets new audio output device for track's DOM elements. Video tracks are
317
+ * ignored.
317 318
  * @param {string} audioOutputDeviceId - id of 'audiooutput' device from
318
- *      navigator.mediaDevices.enumerateDevices()
319
+ *      navigator.mediaDevices.enumerateDevices(), '' for default device
319 320
  * @emits JitsiTrackEvents.TRACK_AUDIO_OUTPUT_CHANGED
320 321
  * @returns {Promise}
321 322
  */
322 323
 JitsiTrack.prototype.setAudioOutput = function (audioOutputDeviceId) {
323 324
     var self = this;
324 325
 
325
-    if (!RTCUtils.isAudioOutputDeviceChangeAvailable()) {
326
+    if (!RTCUtils.isDeviceChangeAvailable('output')) {
326 327
         return Promise.reject(
327 328
             new Error('Audio output device change is not supported'));
328 329
     }
329 330
 
331
+    // All audio communication is done through audio tracks, so ignore changing
332
+    // audio output for video tracks at all.
333
+    if (this.isVideoTrack()) {
334
+        return Promise.resolve();
335
+    }
336
+
330 337
     return Promise.all(this.containers.map(function(element) {
331 338
         return element.setSinkId(audioOutputDeviceId)
332 339
             .catch(function (error) {
333
-                console.error('Failed to change audio output device on element',
340
+                logger.error('Failed to change audio output device on element',
334 341
                     element, error);
335 342
 
336
-                // TODO: for some reason 'AbortError' is raised on video
337
-                // elements with local track blobs. Maybe this is something
338
-                // similar to https://goo.gl/TKLiqx. Ignoring this error for
339
-                // now. Spec says that "If the device identified by the given
340
-                // sinkId cannot be used due to a unspecified error, throw a
341
-                // DOMException whose name is AbortError."
342
-                // In any case, all audio communication is done via separate
343
-                // audio elements, so maybe it doesn't make sense to change
344
-                // sinkId for <video> elements at all.
345
-                if (!(self.isVideoTrack() && self.isLocal && self.isLocal() &&
346
-                    error.name === 'AbortError')) {
347 343
                     throw error;
348
-                }
349 344
             });
350 345
     }))
351 346
     .then(function () {

+ 9
- 14
modules/RTC/RTC.js Datei anzeigen

@@ -307,19 +307,14 @@ RTC.isDeviceListAvailable = function () {
307 307
 };
308 308
 
309 309
 /**
310
- * Returns true if changing the camera / microphone device is supported and
311
- * false if not.
312
- */
313
-RTC.isDeviceChangeAvailable = function () {
314
-    return RTCUtils.isDeviceChangeAvailable();
315
-};
316
-
317
-/**
318
- * Returns true if changing the audio output of media elements is supported
319
- * and false if not.
310
+ * Returns true if changing the input (camera / microphone) or output
311
+ * (audio) device is supported and false if not.
312
+ * @params {string} [deviceType] - type of device to change. Default is
313
+ *      undefined or 'input', 'output' - for audio output device change.
314
+ * @returns {boolean} true if available, false otherwise.
320 315
  */
321
-RTC.isAudioOutputDeviceChangeAvailable = function () {
322
-    return RTCUtils.isAudioOutputDeviceChangeAvailable();
316
+RTC.isDeviceChangeAvailable = function (deviceType) {
317
+    return RTCUtils.isDeviceChangeAvailable(deviceType);
323 318
 };
324 319
 
325 320
 /**
@@ -346,11 +341,11 @@ RTC.setAudioOutputDevice = function (deviceId) {
346 341
  * Returns <tt>true<tt/> if given WebRTC MediaStream is considered a valid
347 342
  * "user" stream which means that it's not a "receive only" stream nor a "mixed"
348 343
  * JVB stream.
349
- * 
344
+ *
350 345
  * Clients that implement Unified Plan, such as Firefox use recvonly
351 346
  * "streams/channels/tracks" for receiving remote stream/tracks, as opposed to
352 347
  * Plan B where there are only 3 channels: audio, video and data.
353
- * 
348
+ *
354 349
  * @param stream WebRTC MediaStream instance
355 350
  * @returns {boolean}
356 351
  */

+ 30
- 24
modules/RTC/RTCUtils.js Datei anzeigen

@@ -26,7 +26,9 @@ var devices = {
26 26
 
27 27
 var audioOuputDeviceId = ''; // default device
28 28
 
29
-var featureDetectionVideoEl = document.createElement('video');
29
+var featureDetectionAudioEl = document.createElement('audio');
30
+var isAudioOutputDeviceChangeAvailable =
31
+    typeof featureDetectionAudioEl.setSinkId !== 'undefined';
30 32
 
31 33
 var rtcReady = false;
32 34
 
@@ -338,9 +340,12 @@ function enumerateDevicesThroughMediaStreamTrack (callback) {
338 340
             return {
339 341
                 facing: source.facing || null,
340 342
                 label: source.label,
341
-                // theoretically deprecated MediaStreamTrack.getSources should not return 'audiooutput' devices but
342
-                // let's handle it in any case
343
-                kind: kind ? (kind === 'audiooutput' ? kind : kind + 'input') : null,
343
+                // theoretically deprecated MediaStreamTrack.getSources should
344
+                // not return 'audiooutput' devices but let's handle it in any
345
+                // case
346
+                kind: kind
347
+                    ? (kind === 'audiooutput' ? kind : kind + 'input')
348
+                    : null,
344 349
                 deviceId: source.id,
345 350
                 groupId: source.groupId || null
346 351
             };
@@ -462,10 +467,11 @@ function wrapAttachMediaStream(origAttachMediaStream) {
462 467
     return function(element, stream) {
463 468
         var res = origAttachMediaStream.apply(RTCUtils, arguments);
464 469
 
465
-        if (RTCUtils.isAudioOutputDeviceChangeAvailable()) {
470
+        if (RTCUtils.isDeviceChangeAvailable('output') &&
471
+            stream.getAudioTracks && stream.getAudioTracks().length) {
466 472
             element.setSinkId(RTCUtils.getAudioOutputDevice())
467 473
                 .catch(function (ex) {
468
-                    console.error('Failed to set audio output on element',
474
+                    logger.error('Failed to set audio output on element',
469 475
                         element, ex);
470 476
                 });
471 477
         }
@@ -847,21 +853,19 @@ var RTCUtils = {
847 853
         return (MediaStreamTrack && MediaStreamTrack.getSources)? true : false;
848 854
     },
849 855
     /**
850
-     * Returns true if changing the camera / microphone device is supported and
851
-     * false if not.
852
-     */
853
-    isDeviceChangeAvailable: function () {
854
-        return RTCBrowserType.isChrome() ||
855
-            RTCBrowserType.isFirefox() ||
856
-            RTCBrowserType.isOpera() ||
857
-            RTCBrowserType.isTemasysPluginUsed();
858
-    },
859
-    /**
860
-     * Returns true if changing the audio output of media elements is supported
861
-     * and false if not.
856
+     * Returns true if changing the input (camera / microphone) or output
857
+     * (audio) device is supported and false if not.
858
+     * @params {string} [deviceType] - type of device to change. Default is
859
+     *      undefined or 'input', 'output' - for audio output device change.
860
+     * @returns {boolean} true if available, false otherwise.
862 861
      */
863
-    isAudioOutputDeviceChangeAvailable: function () {
864
-        return typeof featureDetectionVideoEl.setSinkId !== 'undefined';
862
+    isDeviceChangeAvailable: function (deviceType) {
863
+        return deviceType === 'output' || deviceType === 'audiooutput'
864
+            ? isAudioOutputDeviceChangeAvailable
865
+            : RTCBrowserType.isChrome() ||
866
+                RTCBrowserType.isFirefox() ||
867
+                RTCBrowserType.isOpera() ||
868
+                RTCBrowserType.isTemasysPluginUsed();
865 869
     },
866 870
     /**
867 871
      * A method to handle stopping of the stream.
@@ -896,20 +900,22 @@ var RTCUtils = {
896 900
     /**
897 901
      * Sets current audio output device.
898 902
      * @param {string} deviceId - id of 'audiooutput' device from
899
-     *      navigator.mediaDevices.enumerateDevices()
903
+     *      navigator.mediaDevices.enumerateDevices(), '' for default device
900 904
      * @returns {Promise} - resolves when audio output is changed, is rejected
901 905
      *      otherwise
902 906
      */
903 907
     setAudioOutputDevice: function (deviceId) {
904
-        if (!this.isAudioOutputDeviceChangeAvailable()) {
908
+        if (!this.isDeviceChangeAvailable('output')) {
905 909
             Promise.reject(
906 910
                 new Error('Audio output device change is not supported'));
907 911
         }
908
-        
909
-        return featureDetectionVideoEl.setSinkId(deviceId)
912
+
913
+        return featureDetectionAudioEl.setSinkId(deviceId)
910 914
             .then(function() {
911 915
                 audioOuputDeviceId = deviceId;
912 916
 
917
+                logger.log('Audio output device set to ' + deviceId);
918
+
913 919
                 eventEmitter.emit(RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED,
914 920
                     deviceId);
915 921
             });

Laden…
Abbrechen
Speichern