Browse Source

Splits Simulcast into NativeSimulcast, GrumpySimulcast and NoSimulcast.

j8
George Politis 10 years ago
parent
commit
12957fecc2
2 changed files with 451 additions and 256 deletions
  1. 2
    2
      index.html
  2. 449
    254
      simulcast.js

+ 2
- 2
index.html View File

@@ -10,7 +10,8 @@
10 10
     <meta itemprop="description" content="Join a WebRTC video conference powered by the Jitsi Videobridge"/>
11 11
     <meta itemprop="image" content="/images/jitsilogo.png"/>
12 12
     <script src="libs/jquery-2.1.1.min.js"></script>
13
-    <script src="simulcast.js?v=1"></script><!-- simulcast handling -->
13
+    <script src="config.js?v=5"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
14
+    <script src="simulcast.js?v=2"></script><!-- simulcast handling -->
14 15
     <script src="libs/strophe/strophe.jingle.adapter.js?v=1"></script><!-- strophe.jingle bundles -->
15 16
     <script src="libs/strophe/strophe.min.js?v=1"></script>
16 17
     <script src="libs/strophe/strophe.disco.min.js?v=1"></script>
@@ -27,7 +28,6 @@
27 28
     <script src="libs/rayo.js?v=1"></script>
28 29
     <script src="libs/tooltip.js?v=1"></script><!-- bootstrap tooltip lib -->
29 30
     <script src="libs/popover.js?v=1"></script><!-- bootstrap tooltip lib -->
30
-    <script src="config.js?v=5"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
31 31
     <script src="interface_config.js?v=2"></script>
32 32
     <script src="brand.js?v=1"></script>
33 33
     <script src="muc.js?v=14"></script><!-- simple MUC library -->

+ 449
- 254
simulcast.js View File

@@ -7,12 +7,6 @@
7 7
 function Simulcast() {
8 8
     "use strict";
9 9
 
10
-    // TODO(gp) split the Simulcast class in two classes : NativeSimulcast and ClassicSimulcast.
11
-
12
-    // Once we properly support native simulcast, enable it automatically in the
13
-    // supported browsers (Chrome).
14
-    this.useNativeSimulcast = false;
15
-
16 10
     // TODO(gp) we need a logging framework for javascript à la log4j or the
17 11
     // java logging framework that allows for selective log display
18 12
     this.debugLvl = 0;
@@ -336,7 +330,7 @@ Simulcast.prototype = {
336 330
     },
337 331
 
338 332
     _appendSimulcastGroup: function (lines) {
339
-        var videoSources, ssrcGroup, simSSRC, numOfSubs = 3, i, sb, msid;
333
+        var videoSources, ssrcGroup, simSSRC, numOfSubs = 2, i, sb, msid;
340 334
 
341 335
         if (this.debugLvl) {
342 336
             console.info('Appending simulcast group...');
@@ -442,40 +436,6 @@ Simulcast.prototype = {
442 436
         return sb;
443 437
     },
444 438
 
445
-    /**
446
-     * Ensures that the simulcast group is present in the answer, _if_ native
447
-     * simulcast is enabled,
448
-     *
449
-     * @param desc
450
-     * @returns {*}
451
-     */
452
-    transformAnswer: function (desc) {
453
-        if (config.enableSimulcast && this.useNativeSimulcast) {
454
-
455
-            var sb = desc.sdp.split('\r\n');
456
-
457
-            // Even if we have enabled native simulcasting previously
458
-            // (with a call to SLD with an appropriate SDP, for example),
459
-            // createAnswer seems to consistently generate incomplete SDP
460
-            // with missing SSRCS.
461
-            //
462
-            // So, subsequent calls to SLD will have missing SSRCS and presence
463
-            // won't have the complete list of SRCs.
464
-            this._ensureSimulcastGroup(sb);
465
-
466
-            desc = new RTCSessionDescription({
467
-                type: desc.type,
468
-                sdp: sb.join('\r\n')
469
-            });
470
-
471
-            if (this.debugLvl && this.debugLvl > 1) {
472
-                console.info('Transformed answer');
473
-                console.info(desc.sdp);
474
-            }
475
-        }
476
-
477
-        return desc;
478
-    },
479 439
 
480 440
     _restoreSimulcastGroups: function (sb) {
481 441
         this._restoreRemoteVideoSources(sb);
@@ -511,55 +471,6 @@ Simulcast.prototype = {
511 471
         return desc;
512 472
     },
513 473
 
514
-    /**
515
-     * Prepares the local description for public usage (i.e. to be signaled
516
-     * through Jingle to the focus).
517
-     *
518
-     * @param desc
519
-     * @returns {RTCSessionDescription}
520
-     */
521
-    reverseTransformLocalDescription: function (desc) {
522
-        var sb;
523
-
524
-        if (!desc || desc == null) {
525
-            return desc;
526
-        }
527
-
528
-        if (config.enableSimulcast) {
529
-
530
-            if (this.useNativeSimulcast) {
531
-                sb = desc.sdp.split('\r\n');
532
-
533
-                this._explodeLocalSimulcastSources(sb);
534
-
535
-                desc = new RTCSessionDescription({
536
-                    type: desc.type,
537
-                    sdp: sb.join('\r\n')
538
-                });
539
-
540
-                if (this.debugLvl && this.debugLvl > 1) {
541
-                    console.info('Exploded local video sources');
542
-                    console.info(desc.sdp);
543
-                }
544
-            } else {
545
-                sb = desc.sdp.split('\r\n');
546
-
547
-                this._groupLocalVideoSources(sb);
548
-
549
-                desc = new RTCSessionDescription({
550
-                    type: desc.type,
551
-                    sdp: sb.join('\r\n')
552
-                });
553
-
554
-                if (this.debugLvl && this.debugLvl > 1) {
555
-                    console.info('Grouped local video sources');
556
-                    console.info(desc.sdp);
557
-                }
558
-            }
559
-        }
560
-
561
-        return desc;
562
-    },
563 474
 
564 475
     _ensureOrder: function (lines) {
565 476
         var videoSources, sb;
@@ -593,70 +504,6 @@ Simulcast.prototype = {
593 504
         }
594 505
     },
595 506
 
596
-    /**
597
-     *
598
-     *
599
-     * @param desc
600
-     * @returns {*}
601
-     */
602
-    transformLocalDescription: function (desc) {
603
-        if (config.enableSimulcast && !this.useNativeSimulcast) {
604
-
605
-            var sb = desc.sdp.split('\r\n');
606
-
607
-            this._removeSimulcastGroup(sb);
608
-
609
-            desc = new RTCSessionDescription({
610
-                type: desc.type,
611
-                sdp: sb.join('\r\n')
612
-            });
613
-
614
-            if (this.debugLvl && this.debugLvl > 1) {
615
-                console.info('Transformed local description');
616
-                console.info(desc.sdp);
617
-            }
618
-        }
619
-
620
-        return desc;
621
-    },
622
-
623
-    /**
624
-     * Removes the ssrc-group:SIM from the remote description bacause Chrome
625
-     * either gets confused and thinks this is an FID group or, if an FID group
626
-     * is already present, it fails to set the remote description.
627
-     *
628
-     * @param desc
629
-     * @returns {*}
630
-     */
631
-    transformRemoteDescription: function (desc) {
632
-        if (config.enableSimulcast) {
633
-
634
-            var sb = desc.sdp.split('\r\n');
635
-
636
-            this._updateRemoteMaps(sb);
637
-            this._cacheRemoteVideoSources(sb);
638
-            this._removeSimulcastGroup(sb); // NOTE(gp) this needs to be called after updateRemoteMaps because we need the simulcast group in the _updateRemoteMaps() method.
639
-
640
-            if (this.useNativeSimulcast) {
641
-                // We don't need the goog conference flag if we're not doing
642
-                // native simulcast.
643
-                this._ensureGoogConference(sb);
644
-            }
645
-
646
-            desc = new RTCSessionDescription({
647
-                type: desc.type,
648
-                sdp: sb.join('\r\n')
649
-            });
650
-
651
-            if (this.debugLvl && this.debugLvl > 1) {
652
-                console.info('Transformed remote description');
653
-                console.info(desc.sdp);
654
-            }
655
-        }
656
-
657
-        return desc;
658
-    },
659
-
660 507
     _setReceivingVideoStream: function (endpoint, ssrc) {
661 508
         this.remoteMaps.receivingVideoStreams[endpoint] = ssrc;
662 509
     },
@@ -709,132 +556,482 @@ Simulcast.prototype = {
709 556
     localStream: null, displayedLocalVideoStream: null,
710 557
 
711 558
     /**
712
-     * GUM for simulcast.
559
+     * Gets the fully qualified msid (stream.id + track.id) associated to the
560
+     * SSRC.
713 561
      *
714
-     * @param constraints
715
-     * @param success
716
-     * @param err
562
+     * @param ssrc
563
+     * @returns {*}
717 564
      */
718
-    getUserMedia: function (constraints, success, err) {
719
-
720
-        // TODO(gp) what if we request a resolution not supported by the hardware?
721
-        // TODO(gp) make the lq stream configurable; although this wouldn't work with native simulcast
722
-        var lqConstraints = {
723
-            audio: false,
724
-            video: {
725
-                mandatory: {
726
-                    maxWidth: 320,
727
-                    maxHeight: 180,
728
-                    maxFrameRate: 15
729
-                }
730
-            }
731
-        };
565
+    getRemoteVideoStreamIdBySSRC: function (ssrc) {
566
+        return this.remoteMaps.ssrc2Msid[ssrc];
567
+    },
732 568
 
733
-        console.log('HQ constraints: ', constraints);
734
-        console.log('LQ constraints: ', lqConstraints);
569
+    parseMedia: function (desc, mediatypes) {
570
+        var lines = desc.sdp.split('\r\n');
571
+        return this._parseMedia(lines, mediatypes);
572
+    },
735 573
 
736
-        if (config.enableSimulcast && !this.useNativeSimulcast) {
574
+    getLocalVideoStream: function () {
575
+        return (this.displayedLocalVideoStream != null)
576
+            ? this.displayedLocalVideoStream
577
+            // in case we have no simulcast at all, i.e. we didn't perform the GUM
578
+            : connection.jingle.localVideo;
579
+    }
580
+};
737 581
 
738
-            // NOTE(gp) if we request the lq stream first webkitGetUserMedia
739
-            // fails randomly. Tested with Chrome 37. As fippo suggested, the
740
-            // reason appears to be that Chrome only acquires the cam once and
741
-            // then downscales the picture (https://code.google.com/p/chromium/issues/detail?id=346616#c11)
742 582
 
743
-            var self = this;
744
-            navigator.webkitGetUserMedia(constraints, function (hqStream) {
583
+function NativeSimulcast() {
584
+    Simulcast.call(this); // call the super constructor.
585
+}
745 586
 
746
-                self.localStream = hqStream;
587
+NativeSimulcast.prototype = Object.create(Simulcast.prototype);
747 588
 
748
-                // reset local maps.
749
-                self.localMaps.msids = [];
750
-                self.localMaps.msid2ssrc = {};
589
+/**
590
+ * GUM for simulcast.
591
+ *
592
+ * @param constraints
593
+ * @param success
594
+ * @param err
595
+ */
596
+NativeSimulcast.prototype.getUserMedia = function (constraints, success, err) {
751 597
 
752
-                // add hq trackid to local map
753
-                self.localMaps.msids.push(hqStream.getVideoTracks()[0].id);
598
+    // There's nothing special to do for native simulcast, so just do a normal GUM.
754 599
 
755
-                navigator.webkitGetUserMedia(lqConstraints, function (lqStream) {
600
+    var self = this;
601
+    navigator.webkitGetUserMedia(constraints, function (hqStream) {
756 602
 
757
-                    self.displayedLocalVideoStream = lqStream;
603
+        // reset local maps.
604
+        self.localMaps.msids = [];
605
+        self.localMaps.msid2ssrc = {};
758 606
 
759
-                    // NOTE(gp) The specification says Array.forEach() will visit
760
-                    // the array elements in numeric order, and that it doesn't
761
-                    // visit elements that don't exist.
607
+        // add hq stream to local map
608
+        self.localMaps.msids.push(hqStream.getVideoTracks()[0].id);
609
+        self.displayedLocalVideoStream = self.localStream = hqStream;
610
+        success(self.localStream);
611
+    }, err);
612
+};
762 613
 
763
-                    // add lq trackid to local map
764
-                    self.localMaps.msids.splice(0, 0, lqStream.getVideoTracks()[0].id);
614
+/**
615
+ * Prepares the local description for public usage (i.e. to be signaled
616
+ * through Jingle to the focus).
617
+ *
618
+ * @param desc
619
+ * @returns {RTCSessionDescription}
620
+ */
621
+NativeSimulcast.prototype.reverseTransformLocalDescription = function (desc) {
622
+    var sb;
765 623
 
766
-                    self.localStream.addTrack(lqStream.getVideoTracks()[0]);
767
-                    success(self.localStream);
768
-                }, err);
769
-            }, err);
770
-        } else {
624
+    if (!desc || desc == null) {
625
+        return desc;
626
+    }
771 627
 
772
-            // There's nothing special to do for native simulcast, so just do a normal GUM.
628
+    if (config.enableSimulcast) {
629
+        sb = desc.sdp.split('\r\n');
773 630
 
774
-            navigator.webkitGetUserMedia(constraints, function (hqStream) {
631
+        this._explodeLocalSimulcastSources(sb);
775 632
 
776
-                // reset local maps.
777
-                self.localMaps.msids = [];
778
-                self.localMaps.msid2ssrc = {};
633
+        desc = new RTCSessionDescription({
634
+            type: desc.type,
635
+            sdp: sb.join('\r\n')
636
+        });
637
+
638
+        if (this.debugLvl && this.debugLvl > 1) {
639
+            console.info('Exploded local video sources');
640
+            console.info(desc.sdp);
641
+        }
642
+    }
643
+
644
+    return desc;
645
+};
646
+
647
+/**
648
+ * Ensures that the simulcast group is present in the answer, _if_ native
649
+ * simulcast is enabled,
650
+ *
651
+ * @param desc
652
+ * @returns {*}
653
+ */
654
+NativeSimulcast.prototype.transformAnswer = function (desc) {
655
+    if (config.enableSimulcast) {
656
+
657
+        var sb = desc.sdp.split('\r\n');
658
+
659
+        // Even if we have enabled native simulcasting previously
660
+        // (with a call to SLD with an appropriate SDP, for example),
661
+        // createAnswer seems to consistently generate incomplete SDP
662
+        // with missing SSRCS.
663
+        //
664
+        // So, subsequent calls to SLD will have missing SSRCS and presence
665
+        // won't have the complete list of SRCs.
666
+        this._ensureSimulcastGroup(sb);
667
+
668
+        desc = new RTCSessionDescription({
669
+            type: desc.type,
670
+            sdp: sb.join('\r\n')
671
+        });
672
+
673
+        if (this.debugLvl && this.debugLvl > 1) {
674
+            console.info('Transformed answer');
675
+            console.info(desc.sdp);
676
+        }
677
+    }
779 678
 
780
-                // add hq stream to local map
781
-                self.localMaps.msids.push(hqStream.getVideoTracks()[0].id);
782
-                self.displayedLocalVideoStream = this.localStream = hqStream;
679
+    return desc;
680
+};
681
+
682
+
683
+/**
684
+ *
685
+ *
686
+ * @param desc
687
+ * @returns {*}
688
+ */
689
+NativeSimulcast.prototype.transformLocalDescription = function (desc) {
690
+    return desc;
691
+};
692
+
693
+/**
694
+ * Removes the ssrc-group:SIM from the remote description bacause Chrome
695
+ * either gets confused and thinks this is an FID group or, if an FID group
696
+ * is already present, it fails to set the remote description.
697
+ *
698
+ * @param desc
699
+ * @returns {*}
700
+ */
701
+NativeSimulcast.prototype.transformRemoteDescription = function (desc) {
702
+    if (config.enableSimulcast) {
703
+
704
+        var sb = desc.sdp.split('\r\n');
705
+
706
+        this._updateRemoteMaps(sb);
707
+        this._cacheRemoteVideoSources(sb);
708
+        this._removeSimulcastGroup(sb); // NOTE(gp) this needs to be called after updateRemoteMaps because we need the simulcast group in the _updateRemoteMaps() method.
709
+        // We don't need the goog conference flag if we're not doing
710
+        // native simulcast.
711
+        this._ensureGoogConference(sb);
712
+
713
+        desc = new RTCSessionDescription({
714
+            type: desc.type,
715
+            sdp: sb.join('\r\n')
716
+        });
717
+
718
+        if (this.debugLvl && this.debugLvl > 1) {
719
+            console.info('Transformed remote description');
720
+            console.info(desc.sdp);
721
+        }
722
+    }
723
+
724
+    return desc;
725
+};
726
+
727
+NativeSimulcast.prototype._setLocalVideoStreamEnabled = function (ssrc, enabled) {
728
+    // Nothing to do here, native simulcast does that auto-magically.
729
+};
730
+
731
+NativeSimulcast.prototype.constructor = NativeSimulcast;
732
+
733
+function GrumpySimulcast() {
734
+    Simulcast.call(this);
735
+}
736
+
737
+GrumpySimulcast.prototype = Object.create(Simulcast.prototype);
738
+
739
+/**
740
+ * GUM for simulcast.
741
+ *
742
+ * @param constraints
743
+ * @param success
744
+ * @param err
745
+ */
746
+GrumpySimulcast.prototype.getUserMedia = function (constraints, success, err) {
747
+
748
+    // TODO(gp) what if we request a resolution not supported by the hardware?
749
+    // TODO(gp) make the lq stream configurable; although this wouldn't work with native simulcast
750
+    var lqConstraints = {
751
+        audio: false,
752
+        video: {
753
+            mandatory: {
754
+                maxWidth: 320,
755
+                maxHeight: 180,
756
+                maxFrameRate: 15
757
+            }
758
+        }
759
+    };
760
+
761
+    console.log('HQ constraints: ', constraints);
762
+    console.log('LQ constraints: ', lqConstraints);
763
+
764
+    if (config.enableSimulcast) {
765
+
766
+        // NOTE(gp) if we request the lq stream first webkitGetUserMedia
767
+        // fails randomly. Tested with Chrome 37. As fippo suggested, the
768
+        // reason appears to be that Chrome only acquires the cam once and
769
+        // then downscales the picture (https://code.google.com/p/chromium/issues/detail?id=346616#c11)
770
+
771
+        var self = this;
772
+        navigator.webkitGetUserMedia(constraints, function (hqStream) {
773
+
774
+            self.localStream = hqStream;
775
+
776
+            // reset local maps.
777
+            self.localMaps.msids = [];
778
+            self.localMaps.msid2ssrc = {};
779
+
780
+            // add hq trackid to local map
781
+            self.localMaps.msids.push(hqStream.getVideoTracks()[0].id);
782
+
783
+            navigator.webkitGetUserMedia(lqConstraints, function (lqStream) {
784
+
785
+                self.displayedLocalVideoStream = lqStream;
786
+
787
+                // NOTE(gp) The specification says Array.forEach() will visit
788
+                // the array elements in numeric order, and that it doesn't
789
+                // visit elements that don't exist.
790
+
791
+                // add lq trackid to local map
792
+                self.localMaps.msids.splice(0, 0, lqStream.getVideoTracks()[0].id);
793
+
794
+                self.localStream.addTrack(lqStream.getVideoTracks()[0]);
783 795
                 success(self.localStream);
784 796
             }, err);
797
+        }, err);
798
+    }
799
+};
800
+
801
+/**
802
+ * Prepares the local description for public usage (i.e. to be signaled
803
+ * through Jingle to the focus).
804
+ *
805
+ * @param desc
806
+ * @returns {RTCSessionDescription}
807
+ */
808
+GrumpySimulcast.prototype.reverseTransformLocalDescription = function (desc) {
809
+    var sb;
810
+
811
+    if (!desc || desc == null) {
812
+        return desc;
813
+    }
814
+
815
+    if (config.enableSimulcast) {
816
+
817
+
818
+        sb = desc.sdp.split('\r\n');
819
+
820
+        this._groupLocalVideoSources(sb);
821
+
822
+        desc = new RTCSessionDescription({
823
+            type: desc.type,
824
+            sdp: sb.join('\r\n')
825
+        });
826
+
827
+        if (this.debugLvl && this.debugLvl > 1) {
828
+            console.info('Grouped local video sources');
829
+            console.info(desc.sdp);
785 830
         }
786
-    },
831
+    }
787 832
 
788
-    /**
789
-     * Gets the fully qualified msid (stream.id + track.id) associated to the
790
-     * SSRC.
791
-     *
792
-     * @param ssrc
793
-     * @returns {*}
794
-     */
795
-    getRemoteVideoStreamIdBySSRC: function (ssrc) {
796
-        return this.remoteMaps.ssrc2Msid[ssrc];
797
-    },
833
+    return desc;
834
+};
798 835
 
799
-    parseMedia: function (desc, mediatypes) {
800
-        var lines = desc.sdp.split('\r\n');
801
-        return this._parseMedia(lines, mediatypes);
802
-    },
836
+/**
837
+ * Ensures that the simulcast group is present in the answer, _if_ native
838
+ * simulcast is enabled,
839
+ *
840
+ * @param desc
841
+ * @returns {*}
842
+ */
843
+GrumpySimulcast.prototype.transformAnswer = function (desc) {
844
+    return desc;
845
+};
803 846
 
804
-    _setLocalVideoStreamEnabled: function (ssrc, enabled) {
805
-        var trackid;
806 847
 
807
-        var self = this;
808
-        console.log(['Requested to', enabled ? 'enable' : 'disable', ssrc].join(' '));
809
-        if (Object.keys(this.localMaps.msid2ssrc).some(function (tid) {
810
-            // Search for the track id that corresponds to the ssrc
811
-            if (self.localMaps.msid2ssrc[tid] == ssrc) {
812
-                trackid = tid;
813
-                return true;
814
-            }
815
-        }) && self.localStream.getVideoTracks().some(function (track) {
816
-            // Start/stop the track that corresponds to the track id
817
-            if (track.id === trackid) {
818
-                track.enabled = enabled;
819
-                return true;
820
-            }
821
-        })) {
822
-            console.log([trackid, enabled ? 'enabled' : 'disabled'].join(' '));
823
-            $(document).trigger(enabled
824
-                ? 'simulcastlayerstarted'
825
-                : 'simulcastlayerstopped');
826
-        } else {
827
-            console.error("I don't have a local stream with SSRC " + ssrc);
848
+/**
849
+ *
850
+ *
851
+ * @param desc
852
+ * @returns {*}
853
+ */
854
+GrumpySimulcast.prototype.transformLocalDescription = function (desc) {
855
+    if (config.enableSimulcast) {
856
+
857
+        var sb = desc.sdp.split('\r\n');
858
+
859
+        this._removeSimulcastGroup(sb);
860
+
861
+        desc = new RTCSessionDescription({
862
+            type: desc.type,
863
+            sdp: sb.join('\r\n')
864
+        });
865
+
866
+        if (this.debugLvl && this.debugLvl > 1) {
867
+            console.info('Transformed local description');
868
+            console.info(desc.sdp);
828 869
         }
829
-    },
870
+    }
830 871
 
831
-    getLocalVideoStream: function () {
832
-        return (this.displayedLocalVideoStream != null)
833
-            ? this.displayedLocalVideoStream
834
-            // in case we have no simulcast at all, i.e. we didn't perform the GUM
835
-            : connection.jingle.localVideo;
872
+    return desc;
873
+};
874
+
875
+/**
876
+ * Removes the ssrc-group:SIM from the remote description bacause Chrome
877
+ * either gets confused and thinks this is an FID group or, if an FID group
878
+ * is already present, it fails to set the remote description.
879
+ *
880
+ * @param desc
881
+ * @returns {*}
882
+ */
883
+GrumpySimulcast.prototype.transformRemoteDescription = function (desc) {
884
+    if (config.enableSimulcast) {
885
+
886
+        var sb = desc.sdp.split('\r\n');
887
+
888
+        this._updateRemoteMaps(sb);
889
+        this._cacheRemoteVideoSources(sb);
890
+        this._removeSimulcastGroup(sb); // NOTE(gp) this needs to be called after updateRemoteMaps because we need the simulcast group in the _updateRemoteMaps() method.
891
+
892
+        desc = new RTCSessionDescription({
893
+            type: desc.type,
894
+            sdp: sb.join('\r\n')
895
+        });
896
+
897
+        if (this.debugLvl && this.debugLvl > 1) {
898
+            console.info('Transformed remote description');
899
+            console.info(desc.sdp);
900
+        }
901
+    }
902
+
903
+    return desc;
904
+};
905
+
906
+GrumpySimulcast.prototype._setLocalVideoStreamEnabled = function (ssrc, enabled) {
907
+    var trackid;
908
+
909
+    var self = this;
910
+    console.log(['Requested to', enabled ? 'enable' : 'disable', ssrc].join(' '));
911
+    if (Object.keys(this.localMaps.msid2ssrc).some(function (tid) {
912
+        // Search for the track id that corresponds to the ssrc
913
+        if (self.localMaps.msid2ssrc[tid] == ssrc) {
914
+            trackid = tid;
915
+            return true;
916
+        }
917
+    }) && self.localStream.getVideoTracks().some(function (track) {
918
+        // Start/stop the track that corresponds to the track id
919
+        if (track.id === trackid) {
920
+            track.enabled = enabled;
921
+            return true;
922
+        }
923
+    })) {
924
+        console.log([trackid, enabled ? 'enabled' : 'disabled'].join(' '));
925
+        $(document).trigger(enabled
926
+            ? 'simulcastlayerstarted'
927
+            : 'simulcastlayerstopped');
928
+    } else {
929
+        console.error("I don't have a local stream with SSRC " + ssrc);
930
+    }
931
+};
932
+
933
+GrumpySimulcast.prototype.constructor = GrumpySimulcast;
934
+
935
+function NoSimulcast() {
936
+    Simulcast.call(this);
937
+}
938
+
939
+NoSimulcast.prototype = Object.create(Simulcast.prototype);
940
+
941
+/**
942
+ * GUM for simulcast.
943
+ *
944
+ * @param constraints
945
+ * @param success
946
+ * @param err
947
+ */
948
+NoSimulcast.prototype.getUserMedia = function (constraints, success, err) {
949
+    var self = this;
950
+    navigator.webkitGetUserMedia(constraints, function (hqStream) {
951
+
952
+        // reset local maps.
953
+        self.localMaps.msids = [];
954
+        self.localMaps.msid2ssrc = {};
955
+
956
+        // add hq stream to local map
957
+        self.localMaps.msids.push(hqStream.getVideoTracks()[0].id);
958
+        self.displayedLocalVideoStream = self.localStream = hqStream;
959
+        success(self.localStream);
960
+    }, err);
961
+};
962
+
963
+/**
964
+ * Prepares the local description for public usage (i.e. to be signaled
965
+ * through Jingle to the focus).
966
+ *
967
+ * @param desc
968
+ * @returns {RTCSessionDescription}
969
+ */
970
+NoSimulcast.prototype.reverseTransformLocalDescription = function (desc) {
971
+    return desc;
972
+};
973
+
974
+/**
975
+ * Ensures that the simulcast group is present in the answer, _if_ native
976
+ * simulcast is enabled,
977
+ *
978
+ * @param desc
979
+ * @returns {*}
980
+ */
981
+NoSimulcast.prototype.transformAnswer = function (desc) {
982
+    return desc;
983
+};
984
+
985
+
986
+/**
987
+ *
988
+ *
989
+ * @param desc
990
+ * @returns {*}
991
+ */
992
+NoSimulcast.prototype.transformLocalDescription = function (desc) {
993
+    return desc;
994
+};
995
+
996
+/**
997
+ * Removes the ssrc-group:SIM from the remote description bacause Chrome
998
+ * either gets confused and thinks this is an FID group or, if an FID group
999
+ * is already present, it fails to set the remote description.
1000
+ *
1001
+ * @param desc
1002
+ * @returns {*}
1003
+ */
1004
+NoSimulcast.prototype.transformRemoteDescription = function (desc) {
1005
+    return desc;
1006
+};
1007
+
1008
+NoSimulcast.prototype._setLocalVideoStreamEnabled = function (ssrc, enabled) {
1009
+
1010
+};
1011
+
1012
+NoSimulcast.prototype.constructor = NoSimulcast;
1013
+
1014
+// Initialize simulcast.
1015
+var simulcast;
1016
+if (!config.enableSimulcast) {
1017
+    simulcast = new NoSimulcast();
1018
+} else {
1019
+
1020
+    var isChromium = window.chrome,
1021
+        vendorName = window.navigator.vendor;
1022
+    if(isChromium !== null && isChromium !== undefined && vendorName === "Google Inc.") {
1023
+        var ver = parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10);
1024
+        if (ver > 37) {
1025
+            simulcast = new NativeSimulcast();
1026
+        } else {
1027
+            simulcast = new NoSimulcast();
1028
+        }
1029
+    } else {
1030
+        simulcast = new NoSimulcast();
836 1031
     }
1032
+
837 1033
 }
1034
+
838 1035
 $(document).bind('simulcastlayerschanged', function (event, endpointSimulcastLayers) {
839 1036
     endpointSimulcastLayers.forEach(function (esl) {
840 1037
         var ssrc = esl.simulcastLayer.primarySSRC;
@@ -850,6 +1047,4 @@ $(document).bind('startsimulcastlayer', function (event, simulcastLayer) {
850 1047
 $(document).bind('stopsimulcastlayer', function (event, simulcastLayer) {
851 1048
     var ssrc = simulcastLayer.primarySSRC;
852 1049
     simulcast._setLocalVideoStreamEnabled(ssrc, false);
853
-});
854
-
855
-var simulcast = new Simulcast();
1050
+});

Loading…
Cancel
Save