|
|
@@ -37,11 +37,11 @@ function Simulcast() {
|
|
37
|
37
|
};
|
|
38
|
38
|
}());
|
|
39
|
39
|
|
|
40
|
|
- Simulcast.prototype._cacheVideoSources = function (lines) {
|
|
|
40
|
+ Simulcast.prototype._cacheLocalVideoSources = function (lines) {
|
|
41
|
41
|
localVideoSourceCache = this._getVideoSources(lines);
|
|
42
|
42
|
};
|
|
43
|
43
|
|
|
44
|
|
- Simulcast.prototype._restoreVideoSources = function (lines) {
|
|
|
44
|
+ Simulcast.prototype._restoreLocalVideoSources = function (lines) {
|
|
45
|
45
|
this._replaceVideoSources(lines, localVideoSourceCache);
|
|
46
|
46
|
};
|
|
47
|
47
|
|
|
|
@@ -183,7 +183,7 @@ function Simulcast() {
|
|
183
|
183
|
};
|
|
184
|
184
|
|
|
185
|
185
|
// Returns a random integer between min (included) and max (excluded)
|
|
186
|
|
- // Using Math.round() will give you a non-uniform distribution!
|
|
|
186
|
+ // Using Math.round() gives a non-uniform distribution!
|
|
187
|
187
|
Simulcast.prototype._generateRandomSSRC = function () {
|
|
188
|
188
|
var min = 0, max = 0xffffffff;
|
|
189
|
189
|
return Math.floor(Math.random() * (max - min)) + min;
|
|
|
@@ -198,6 +198,23 @@ function Simulcast() {
|
|
198
|
198
|
|
|
199
|
199
|
emptyCompoundIndex = new CompoundIndex();
|
|
200
|
200
|
|
|
|
201
|
+ /**
|
|
|
202
|
+ * The _indexOfArray() method returns the first a CompoundIndex at which a
|
|
|
203
|
+ * given element can be found in the array, or emptyCompoundIndex if it is
|
|
|
204
|
+ * not present.
|
|
|
205
|
+ *
|
|
|
206
|
+ * Example:
|
|
|
207
|
+ *
|
|
|
208
|
+ * _indexOfArray('3', [ 'this is line 1', 'this is line 2', 'this is line 3' ])
|
|
|
209
|
+ *
|
|
|
210
|
+ * returns {row: 2, column: 14}
|
|
|
211
|
+ *
|
|
|
212
|
+ * @param needle
|
|
|
213
|
+ * @param haystack
|
|
|
214
|
+ * @param start
|
|
|
215
|
+ * @returns {CompoundIndex}
|
|
|
216
|
+ * @private
|
|
|
217
|
+ */
|
|
201
|
218
|
Simulcast.prototype._indexOfArray = function (needle, haystack, start) {
|
|
202
|
219
|
var length = haystack.length, idx, i;
|
|
203
|
220
|
|
|
|
@@ -360,11 +377,11 @@ function Simulcast() {
|
|
360
|
377
|
|
|
361
|
378
|
if (this._indexOfArray('a=ssrc-group:SIM', lines) === emptyCompoundIndex) {
|
|
362
|
379
|
this._appendSimulcastGroup(lines);
|
|
363
|
|
- this._cacheVideoSources(lines);
|
|
|
380
|
+ this._cacheLocalVideoSources(lines);
|
|
364
|
381
|
} else {
|
|
365
|
382
|
// verify that the ssrcs participating in the SIM group are present
|
|
366
|
383
|
// in the SDP (needed for presence).
|
|
367
|
|
- this._restoreVideoSources(lines);
|
|
|
384
|
+ this._restoreLocalVideoSources(lines);
|
|
368
|
385
|
}
|
|
369
|
386
|
};
|
|
370
|
387
|
|
|
|
@@ -550,14 +567,12 @@ function Simulcast() {
|
|
550
|
567
|
};
|
|
551
|
568
|
|
|
552
|
569
|
Simulcast.prototype._updateRemoteMaps = function (lines) {
|
|
553
|
|
- var remoteVideoSources = this._parseMedia(lines, ['video'])[0], videoSource, quality;
|
|
|
570
|
+ var remoteVideoSources = this._parseMedia(lines, ['video'])[0],
|
|
|
571
|
+ videoSource, quality;
|
|
554
|
572
|
|
|
555
|
573
|
// (re) initialize the remote maps.
|
|
556
|
|
- remoteMaps = {
|
|
557
|
|
- msid2Quality: {},
|
|
558
|
|
- ssrc2Msid: {},
|
|
559
|
|
- receivingVideoStreams: {}
|
|
560
|
|
- };
|
|
|
574
|
+ remoteMaps.msid2Quality = {};
|
|
|
575
|
+ remoteMaps.ssrc2Msid = {};
|
|
561
|
576
|
|
|
562
|
577
|
if (remoteVideoSources.groups && remoteVideoSources.groups.length !== 0) {
|
|
563
|
578
|
remoteVideoSources.groups.forEach(function (group) {
|
|
|
@@ -637,11 +652,8 @@ function Simulcast() {
|
|
637
|
652
|
return desc;
|
|
638
|
653
|
};
|
|
639
|
654
|
|
|
640
|
|
- Simulcast.prototype._setReceivingVideoStream = function (ssrc) {
|
|
641
|
|
- var receivingTrack = remoteMaps.ssrc2Msid[ssrc],
|
|
642
|
|
- msidParts = receivingTrack.split(' ');
|
|
643
|
|
-
|
|
644
|
|
- remoteMaps.receivingVideoStreams[msidParts[0]] = msidParts[1];
|
|
|
655
|
+ Simulcast.prototype._setReceivingVideoStream = function (endpoint, ssrc) {
|
|
|
656
|
+ remoteMaps.receivingVideoStreams[endpoint] = ssrc;
|
|
645
|
657
|
};
|
|
646
|
658
|
|
|
647
|
659
|
/**
|
|
|
@@ -652,22 +664,20 @@ function Simulcast() {
|
|
652
|
664
|
* @returns {webkitMediaStream}
|
|
653
|
665
|
*/
|
|
654
|
666
|
Simulcast.prototype.getReceivingVideoStream = function (stream) {
|
|
655
|
|
- var tracks, i, electedTrack, msid, quality = 1, receivingTrackId;
|
|
|
667
|
+ var tracks, i, electedTrack, msid, quality = 0, receivingTrackId;
|
|
656
|
668
|
|
|
657
|
669
|
if (config.enableSimulcast) {
|
|
658
|
670
|
|
|
659
|
|
- if (remoteMaps.receivingVideoStreams[stream.id])
|
|
660
|
|
- {
|
|
661
|
|
- // the bridge has signaled us to receive a specific track.
|
|
662
|
|
- receivingTrackId = remoteMaps.receivingVideoStreams[stream.id];
|
|
663
|
|
- tracks = stream.getVideoTracks();
|
|
664
|
|
- for (i = 0; i < tracks.length; i++) {
|
|
665
|
|
- if (receivingTrackId === tracks[i].id) {
|
|
666
|
|
- electedTrack = tracks[i];
|
|
667
|
|
- break;
|
|
|
671
|
+ stream.getVideoTracks().some(function(track) {
|
|
|
672
|
+ return Object.keys(remoteMaps.receivingVideoStreams).some(function(endpoint) {
|
|
|
673
|
+ var ssrc = remoteMaps.receivingVideoStreams[endpoint];
|
|
|
674
|
+ var msid = remoteMaps.ssrc2Msid[ssrc];
|
|
|
675
|
+ if (msid == [stream.id, track.id].join(' ')) {
|
|
|
676
|
+ electedTrack = track;
|
|
|
677
|
+ return true;
|
|
668
|
678
|
}
|
|
669
|
|
- }
|
|
670
|
|
- }
|
|
|
679
|
+ });
|
|
|
680
|
+ });
|
|
671
|
681
|
|
|
672
|
682
|
if (!electedTrack) {
|
|
673
|
683
|
// we don't have an elected track, choose by initial quality.
|
|
|
@@ -708,11 +718,15 @@ function Simulcast() {
|
|
708
|
718
|
video: {
|
|
709
|
719
|
mandatory: {
|
|
710
|
720
|
maxWidth: 320,
|
|
711
|
|
- maxHeight: 180
|
|
|
721
|
+ maxHeight: 180,
|
|
|
722
|
+ maxFrameRate: 15
|
|
712
|
723
|
}
|
|
713
|
724
|
}
|
|
714
|
725
|
};
|
|
715
|
726
|
|
|
|
727
|
+ console.log('HQ constraints: ', constraints);
|
|
|
728
|
+ console.log('LQ constraints: ', lqConstraints);
|
|
|
729
|
+
|
|
716
|
730
|
if (config.enableSimulcast && !config.useNativeSimulcast) {
|
|
717
|
731
|
|
|
718
|
732
|
// NOTE(gp) if we request the lq stream first webkitGetUserMedia
|
|
|
@@ -777,42 +791,30 @@ function Simulcast() {
|
|
777
|
791
|
return this._parseMedia(lines, mediatypes);
|
|
778
|
792
|
};
|
|
779
|
793
|
|
|
780
|
|
- Simulcast.prototype._startLocalVideoStream = function (ssrc) {
|
|
|
794
|
+ Simulcast.prototype._setLocalVideoStreamEnabled = function (ssrc, enabled) {
|
|
781
|
795
|
var trackid;
|
|
782
|
796
|
|
|
783
|
|
- Object.keys(localMaps.msid2ssrc).some(function (tid) {
|
|
784
|
|
- if (localMaps.msid2ssrc[tid] == ssrc)
|
|
785
|
|
- {
|
|
|
797
|
+ console.log(['Requested to', enabled ? 'enable' : 'disable', ssrc].join(' '));
|
|
|
798
|
+ if (Object.keys(localMaps.msid2ssrc).some(function (tid) {
|
|
|
799
|
+ // Search for the track id that corresponds to the ssrc
|
|
|
800
|
+ if (localMaps.msid2ssrc[tid] == ssrc) {
|
|
786
|
801
|
trackid = tid;
|
|
787
|
802
|
return true;
|
|
788
|
803
|
}
|
|
789
|
|
- });
|
|
790
|
|
-
|
|
791
|
|
- stream.getVideoTracks().some(function(track) {
|
|
|
804
|
+ }) && stream.getVideoTracks().some(function(track) {
|
|
|
805
|
+ // Start/stop the track that corresponds to the track id
|
|
792
|
806
|
if (track.id === trackid) {
|
|
793
|
|
- track.enabled = true;
|
|
|
807
|
+ track.enabled = enabled;
|
|
794
|
808
|
return true;
|
|
795
|
809
|
}
|
|
796
|
|
- });
|
|
797
|
|
- };
|
|
798
|
|
-
|
|
799
|
|
- Simulcast.prototype._stopLocalVideoStream = function (ssrc) {
|
|
800
|
|
- var trackid;
|
|
801
|
|
-
|
|
802
|
|
- Object.keys(localMaps.msid2ssrc).some(function (tid) {
|
|
803
|
|
- if (localMaps.msid2ssrc[tid] == ssrc)
|
|
804
|
|
- {
|
|
805
|
|
- trackid = tid;
|
|
806
|
|
- return true;
|
|
807
|
|
- }
|
|
808
|
|
- });
|
|
809
|
|
-
|
|
810
|
|
- stream.getVideoTracks().some(function(track) {
|
|
811
|
|
- if (track.id === trackid) {
|
|
812
|
|
- track.enabled = false;
|
|
813
|
|
- return true;
|
|
814
|
|
- }
|
|
815
|
|
- });
|
|
|
810
|
+ })) {
|
|
|
811
|
+ console.log([trackid, enabled ? 'enabled' : 'disabled'].join(' '));
|
|
|
812
|
+ $(document).trigger(enabled
|
|
|
813
|
+ ? 'simulcastlayerstarted'
|
|
|
814
|
+ : 'simulcastlayerstopped');
|
|
|
815
|
+ } else {
|
|
|
816
|
+ console.error("I don't have a local stream with SSRC " + ssrc);
|
|
|
817
|
+ }
|
|
816
|
818
|
};
|
|
817
|
819
|
|
|
818
|
820
|
Simulcast.prototype.getLocalVideoStream = function() {
|
|
|
@@ -831,21 +833,19 @@ function Simulcast() {
|
|
831
|
833
|
endpointSimulcastLayers.forEach(function (esl) {
|
|
832
|
834
|
var ssrc = esl.simulcastLayer.primarySSRC;
|
|
833
|
835
|
var simulcast = new Simulcast();
|
|
834
|
|
- simulcast._setReceivingVideoStream(ssrc);
|
|
|
836
|
+ simulcast._setReceivingVideoStream(esl.endpoint, ssrc);
|
|
835
|
837
|
});
|
|
836
|
838
|
});
|
|
837
|
839
|
|
|
838
|
840
|
$(document).bind('startsimulcastlayer', function(event, simulcastLayer) {
|
|
839
|
841
|
var ssrc = simulcastLayer.primarySSRC;
|
|
840
|
842
|
var simulcast = new Simulcast();
|
|
841
|
|
- simulcast._startLocalVideoStream(ssrc);
|
|
842
|
|
- $(document).trigger('simulcastlayerstarted');
|
|
|
843
|
+ simulcast._setLocalVideoStreamEnabled(ssrc, true);
|
|
843
|
844
|
});
|
|
844
|
845
|
|
|
845
|
846
|
$(document).bind('stopsimulcastlayer', function(event, simulcastLayer) {
|
|
846
|
847
|
var ssrc = simulcastLayer.primarySSRC;
|
|
847
|
848
|
var simulcast = new Simulcast();
|
|
848
|
|
- simulcast._stopLocalVideoStream(ssrc);
|
|
849
|
|
- $(document).trigger('simulcastlayerstopped');
|
|
|
849
|
+ simulcast._setLocalVideoStreamEnabled(ssrc, false);
|
|
850
|
850
|
});
|
|
851
|
851
|
}());
|