|
|
@@ -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 "videoSrc" 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 "videoSrc" 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
|
/**
|