Browse Source

Merge pull request #128 from jitsi/native-track-attach

Reduce the dependency on HTML elements
master
hristoterezov 9 years ago
parent
commit
2112cc97b9
4 changed files with 156 additions and 92 deletions
  1. 15
    23
      modules/RTC/JitsiTrack.js
  2. 0
    4
      modules/RTC/RTC.js
  3. 1
    9
      modules/RTC/RTCUIHelper.js
  4. 140
    56
      modules/RTC/RTCUtils.js

+ 15
- 23
modules/RTC/JitsiTrack.js View File

@@ -174,15 +174,7 @@ JitsiTrack.prototype._maybeFireTrackAttached = function (container) {
174 174
  */
175 175
 JitsiTrack.prototype.attach = function (container) {
176 176
     if(this.stream) {
177
-        // The container must be visible in order to play or attach the stream
178
-        // when Temasys plugin is in use
179
-        var containerSel = $(container);
180
-        if (RTCBrowserType.isTemasysPluginUsed() &&
181
-            !containerSel.is(':visible')) {
182
-            containerSel.show();
183
-        }
184
-        container
185
-            = RTCUtils.attachMediaStream(container, this.stream);
177
+        container = RTCUtils.attachMediaStream(container, this.stream);
186 178
     }
187 179
     this.containers.push(container);
188 180
 
@@ -192,26 +184,26 @@ JitsiTrack.prototype.attach = function (container) {
192 184
 };
193 185
 
194 186
 /**
195
- * Removes the track from the passed HTML container.
196
- * @param container the HTML container. If <tt>null</tt> all containers are removed.
197
- *        A container can be 'video', 'audio' or 'object' HTML element instance
198
- *        to which this JitsiTrack is currently attached to.
187
+ * Removes this JitsiTrack from the passed HTML container.
188
+ *
189
+ * @param container the HTML container to detach from this JitsiTrack. If
190
+ * <tt>null</tt> or <tt>undefined</tt>, all containers are removed. A container
191
+ * can be a 'video', 'audio' or 'object' HTML element instance to which this
192
+ * JitsiTrack is currently attached.
199 193
  */
200 194
 JitsiTrack.prototype.detach = function (container) {
201
-    for(var i = 0; i < this.containers.length; i++)
202
-    {
203
-        if(!container)
204
-        {
205
-            RTCUtils.setVideoSrc(this.containers[i], null);
195
+    for (var cs = this.containers, i = cs.length - 1; i >= 0; --i) {
196
+        var c = cs[i];
197
+        if (!container) {
198
+            RTCUtils.attachMediaStream(c, null);
206 199
         }
207
-        if(!container || $(this.containers[i]).is($(container)))
208
-        {
209
-            this.containers.splice(i,1);
200
+        if (!container || c === container) {
201
+            cs.splice(i, 1);
210 202
         }
211 203
     }
212 204
 
213
-    if(container) {
214
-        RTCUtils.setVideoSrc(container, null);
205
+    if (container) {
206
+        RTCUtils.attachMediaStream(container, null);
215 207
     }
216 208
 };
217 209
 

+ 0
- 4
modules/RTC/RTC.js View File

@@ -381,10 +381,6 @@ RTC.enumerateDevices = function (callback) {
381 381
     RTCUtils.enumerateDevices(callback);
382 382
 };
383 383
 
384
-RTC.setVideoSrc = function (element, src) {
385
-    RTCUtils.setVideoSrc(element, src);
386
-};
387
-
388 384
 /**
389 385
  * A method to handle stopping of the stream.
390 386
  * One point to handle the differences in various implementations.

+ 1
- 9
modules/RTC/RTCUIHelper.js View File

@@ -69,15 +69,7 @@ var RTCUIHelper = {
69 69
      */
70 70
     getVideoId: function (element) {
71 71
         var src = RTC.getVideoSrc(element);
72
-        if (!src) {
73
-            return "";
74
-        }
75
-
76
-        if (RTCBrowserType.isFirefox()) {
77
-            return src.id;
78
-        }
79
-
80
-        return src;
72
+        return src ? String(src) : '';
81 73
     }
82 74
 };
83 75
 

+ 140
- 56
modules/RTC/RTCUtils.js View File

@@ -578,8 +578,10 @@ function wrapAttachMediaStream(origAttachMediaStream) {
578 578
     return function(element, stream) {
579 579
         var res = origAttachMediaStream.apply(RTCUtils, arguments);
580 580
 
581
-        if (RTCUtils.isDeviceChangeAvailable('output') &&
582
-            stream.getAudioTracks && stream.getAudioTracks().length) {
581
+        if (stream
582
+                && RTCUtils.isDeviceChangeAvailable('output')
583
+                && stream.getAudioTracks
584
+                && stream.getAudioTracks().length) {
583 585
             element.setSinkId(RTCUtils.getAudioOutputDevice())
584 586
                 .catch(function (ex) {
585 587
                     var err = new JitsiTrackError(ex, null, ['audiooutput']);
@@ -598,6 +600,107 @@ function wrapAttachMediaStream(origAttachMediaStream) {
598 600
     }
599 601
 }
600 602
 
603
+/**
604
+ * Represents a default implementation of {@link RTCUtils#getVideoSrc} which
605
+ * tries to be browser-agnostic through feature checking. Note though that it
606
+ * was not completely clear from the predating browser-specific implementations
607
+ * what &quot;videoSrc&quot; was because one implementation would return
608
+ * <tt>MediaStream</tt> (e.g. Firefox), another a <tt>string</tt> representation
609
+ * of the <tt>URL</tt> of the <tt>MediaStream</tt> (e.g. Chrome) and the return
610
+ * value was only used by {@link RTCUIHelper#getVideoId} which itself did not
611
+ * appear to be used anywhere. Generally, the implementation will try to follow
612
+ * the related standards i.e. work with the <tt>srcObject</tt> and <tt>src</tt>
613
+ * properties of the specified <tt>element</tt> taking into account vender
614
+ * prefixes.
615
+ *
616
+ * @param element the element to get the associated video source/src of
617
+ * @return the video source/src of the specified <tt>element</tt>
618
+ */
619
+function defaultGetVideoSrc(element) {
620
+    // https://www.w3.org/TR/mediacapture-streams/
621
+    //
622
+    // User Agents that support this specification must support the srcObject
623
+    // attribute of the HTMLMediaElement interface defined in [HTML51].
624
+
625
+    // https://www.w3.org/TR/2015/WD-html51-20150506/semantics.html#dom-media-srcobject
626
+    //
627
+    // There are three ways to specify a media resource: the srcObject IDL
628
+    // attribute, the src content attribute, and source elements. The IDL
629
+    // attribute takes priority, followed by the content attribute, followed by
630
+    // the elements.
631
+
632
+    // srcObject
633
+    var srcObject = element.srcObject || element.mozSrcObject;
634
+    if (srcObject) {
635
+        // Try the optimized path to the URL of a MediaStream.
636
+        var url = srcObject.jitsiObjectURL;
637
+        if (url) {
638
+            return url.toString();
639
+        }
640
+        // Go via the unoptimized path to the URL of a MediaStream then.
641
+        var URL = (window.URL || webkitURL);
642
+        if (URL) {
643
+            url = URL.createObjectURL(srcObject);
644
+            try {
645
+                return url.toString();
646
+            } finally {
647
+                URL.revokeObjectURL(url);
648
+            }
649
+        }
650
+    }
651
+
652
+    // src
653
+    return element.src;
654
+}
655
+
656
+/**
657
+ * Represents a default implementation of setting a <tt>MediaStream</tt> as the
658
+ * source of a video element that tries to be browser-agnostic through feature
659
+ * checking. Note though that it was not completely clear from the predating
660
+ * browser-specific implementations what &quot;videoSrc&quot; was because one
661
+ * implementation of {@link RTCUtils#getVideoSrc} would return
662
+ * <tt>MediaStream</tt> (e.g. Firefox), another a <tt>string</tt> representation
663
+ * of the <tt>URL</tt> of the <tt>MediaStream</tt> (e.g. Chrome) and the return
664
+ * value was only used by {@link RTCUIHelper#getVideoId} which itself did not
665
+ * appear to be used anywhere. Generally, the implementation will try to follow
666
+ * the related standards i.e. work with the <tt>srcObject</tt> and <tt>src</tt>
667
+ * properties of the specified <tt>element</tt> taking into account vender
668
+ * prefixes.
669
+ *
670
+ * @param element the element whose video source/src is to be set to the
671
+ * specified <tt>stream</tt>
672
+ * @param {MediaStream} stream the <tt>MediaStream</tt> to set as the video
673
+ * source/src of <tt>element</tt>
674
+ */
675
+function defaultSetVideoSrc(element, stream) {
676
+    // srcObject
677
+    var srcObjectPropertyName = 'srcObject';
678
+    if (!(srcObjectPropertyName in element)) {
679
+        srcObjectPropertyName = 'mozSrcObject';
680
+        if (!(srcObjectPropertyName in element)) {
681
+            srcObjectPropertyName = null;
682
+        }
683
+    }
684
+    if (srcObjectPropertyName) {
685
+        element[srcObjectPropertyName] = stream;
686
+        return;
687
+    }
688
+
689
+    // src
690
+    var src;
691
+    if (stream) {
692
+        src = stream.jitsiObjectURL;
693
+        // Save the created URL for stream so we can reuse it and not keep
694
+        // creating URLs.
695
+        if (!src) {
696
+            stream.jitsiObjectURL
697
+                = src
698
+                    = (URL || webkitURL).createObjectURL(stream);
699
+        }
700
+    }
701
+    element.src = src || '';
702
+}
703
+
601 704
 //Options parameter is to pass config options. Currently uses only "useIPv6".
602 705
 var RTCUtils = {
603 706
     init: function (options) {
@@ -636,11 +739,11 @@ var RTCUtils = {
636 739
                     //
637 740
                     // https://groups.google.com/forum/#!topic/mozilla.dev.media/pKOiioXonJg
638 741
                     // https://github.com/webrtc/samples/issues/302
639
-                    if (!element)
640
-                        return;
641
-                    element.mozSrcObject = stream;
642
-                    element.play();
643
-
742
+                    if (element) {
743
+                        defaultSetVideoSrc(element, stream);
744
+                        if (stream)
745
+                            element.play();
746
+                    }
644 747
                     return element;
645 748
                 });
646 749
                 this.getStreamID = function (stream) {
@@ -654,15 +757,7 @@ var RTCUtils = {
654 757
                     }
655 758
                     return SDPUtil.filter_special_chars(id);
656 759
                 };
657
-                this.getVideoSrc = function (element) {
658
-                    if (!element)
659
-                        return null;
660
-                    return element.mozSrcObject;
661
-                };
662
-                this.setVideoSrc = function (element, src) {
663
-                    if (element)
664
-                        element.mozSrcObject = src;
665
-                };
760
+                this.getVideoSrc = defaultGetVideoSrc;
666 761
                 RTCSessionDescription = mozRTCSessionDescription;
667 762
                 RTCIceCandidate = mozRTCIceCandidate;
668 763
             } else if (RTCBrowserType.isChrome() ||
@@ -681,16 +776,7 @@ var RTCUtils = {
681 776
                     this.enumerateDevices = enumerateDevicesThroughMediaStreamTrack;
682 777
                 }
683 778
                 this.attachMediaStream = wrapAttachMediaStream(function (element, stream) {
684
-
685
-                    // saves the created url for the stream, so we can reuse it
686
-                    // and not keep creating urls
687
-                    if (!stream.jitsiObjectURL) {
688
-                        stream.jitsiObjectURL
689
-                            = webkitURL.createObjectURL(stream);
690
-                    }
691
-
692
-                    element.src = stream.jitsiObjectURL;
693
-
779
+                    defaultSetVideoSrc(element, stream);
694 780
                     return element;
695 781
                 });
696 782
                 this.getStreamID = function (stream) {
@@ -709,13 +795,7 @@ var RTCUtils = {
709 795
                             ? id
710 796
                             : SDPUtil.filter_special_chars(id));
711 797
                 };
712
-                this.getVideoSrc = function (element) {
713
-                    return element ? element.getAttribute("src") : null;
714
-                };
715
-                this.setVideoSrc = function (element, src) {
716
-                    if (element)
717
-                        element.setAttribute("src", src || '');
718
-                };
798
+                this.getVideoSrc = defaultGetVideoSrc;
719 799
                 // DTLS should now be enabled by default but..
720 800
                 this.pc_constraints = {'optional': [
721 801
                     {'DtlsSrtpKeyAgreement': 'true'}
@@ -750,14 +830,25 @@ var RTCUtils = {
750 830
                     self.getUserMedia = window.getUserMedia;
751 831
                     self.enumerateDevices = enumerateDevicesThroughMediaStreamTrack;
752 832
                     self.attachMediaStream = wrapAttachMediaStream(function (element, stream) {
833
+                        if (stream) {
834
+                            if (stream.id === "dummyAudio"
835
+                                    || stream.id === "dummyVideo") {
836
+                                return;
837
+                            }
753 838
 
754
-                        if (stream.id === "dummyAudio" || stream.id === "dummyVideo") {
755
-                            return;
756
-                        }
757
-
758
-                        var isVideoStream = !!stream.getVideoTracks().length;
759
-                        if (isVideoStream && !$(element).is(':visible')) {
760
-                            throw new Error('video element must be visible to attach video stream');
839
+                            // The container must be visible in order to play or
840
+                            // attach the stream when Temasys plugin is in use
841
+                            var containerSel = $(element);
842
+                            if (RTCBrowserType.isTemasysPluginUsed()
843
+                                    && !containerSel.is(':visible')) {
844
+                                containerSel.show();
845
+                            }
846
+                            var video = !!stream.getVideoTracks().length;
847
+                            if (video && !$(element).is(':visible')) {
848
+                                throw new Error(
849
+                                    'video element must be visible to attach'
850
+                                        + ' video stream');
851
+                            }
761 852
                         }
762 853
 
763 854
                         return attachMediaStream(element, stream);
@@ -766,8 +857,12 @@ var RTCUtils = {
766 857
                         return SDPUtil.filter_special_chars(stream.label);
767 858
                     };
768 859
                     self.getVideoSrc = function (element) {
860
+                        // There's nothing standard about getVideoSrc in the
861
+                        // case of Temasys so there's no point to try to
862
+                        // generalize it through defaultGetVideoSrc.
769 863
                         if (!element) {
770
-                            logger.warn("Attempt to get video SRC of null element");
864
+                            logger.warn(
865
+                                "Attempt to get video SRC of null element");
771 866
                             return null;
772 867
                         }
773 868
                         var children = element.children;
@@ -779,19 +874,6 @@ var RTCUtils = {
779 874
                         //logger.info(element.id + " SRC: " + src);
780 875
                         return null;
781 876
                     };
782
-                    self.setVideoSrc = function (element, src) {
783
-                        //logger.info("Set video src: ", element, src);
784
-                        if (!src) {
785
-                            attachMediaStream(element, null);
786
-                        } else {
787
-                            AdapterJS.WebRTCPlugin.WaitForPluginReady();
788
-                            var stream
789
-                                = AdapterJS.WebRTCPlugin.plugin
790
-                                    .getStreamWithId(
791
-                                        AdapterJS.WebRTCPlugin.pageId, src);
792
-                            attachMediaStream(element, stream);
793
-                        }
794
-                    };
795 877
 
796 878
                     onReady(options, self.getUserMediaWithConstraints);
797 879
                     resolve();
@@ -1051,8 +1133,10 @@ var RTCUtils = {
1051 1133
         }
1052 1134
 
1053 1135
         // if we have done createObjectURL, lets clean it
1054
-        if (mediaStream.jitsiObjectURL) {
1055
-            webkitURL.revokeObjectURL(mediaStream.jitsiObjectURL);
1136
+        var url = mediaStream.jitsiObjectURL;
1137
+        if (url) {
1138
+            delete mediaStream.jitsiObjectURL;
1139
+            (URL || webkitURL).revokeObjectURL(url);
1056 1140
         }
1057 1141
     },
1058 1142
     /**

Loading…
Cancel
Save