浏览代码

Fixes issues with starting the streams after the conference has been joined.

dev1
hristoterezov 10 年前
父节点
当前提交
86a2e4257a

+ 19
- 8
doc/example/example.js 查看文件

@@ -1,3 +1,13 @@
1
+//var options = {
2
+//    hosts: {
3
+//        domain: "prod-us-east-1-app-xmpp1.internal.meet.hipchat.ninja",
4
+//        focus: "focus.prod-us-east-1-app-xmpp1.internal.meet.hipchat.ninja",
5
+//        muc: "conference.prod-us-east-1-app-xmpp1.internal.meet.hipchat.ninja", // FIXME: use XEP-0030
6
+//    },
7
+//    bosh: "https://xmpp1-meet.hipchat.me/http-bind", // FIXME: use xep-0156 for that
8
+//    clientNode: "http://prod-us-east-1-app-xmpp1.internal.meet.hipchat.ninja/jitsimeet" // The name of client node advertised in XEP-0115 'c' stanza
9
+//};
10
+
1 11
 var options = {
2 12
     hosts: {
3 13
         domain: 'hristo.jitsi.net',
@@ -5,8 +15,8 @@ var options = {
5 15
         bridge: 'jitsi-videobridge.hristo.jitsi.net', // FIXME: use XEP-0030
6 16
     },
7 17
     bosh: '//hristo.jitsi.net/http-bind', // FIXME: use xep-0156 for that
8
-    clientNode: 'http://jitsi.org/jitsimeet' // The name of client node advertised in XEP-0115 'c' stanza
9
-};
18
+    clientNode: 'http://jitsi.org/jitsimeet', // The name of client node advertised in XEP-0115 'c' stanza
19
+}
10 20
 
11 21
 var confOptions = {
12 22
     openSctp: true
@@ -22,6 +32,10 @@ function onLocalTracks(tracks)
22 32
     console.log(tracks);
23 33
     tracks[0].attach($("#localAudio"));
24 34
     tracks[1].attach($("#localVideo"));
35
+    for(var i = 0; i < localTracks.length; i++)
36
+    {
37
+        localTracks[i].start();
38
+    }
25 39
 }
26 40
 
27 41
 /**
@@ -46,10 +60,8 @@ function onRemoteTrack(track) {
46 60
  * That function is executed when the conference is joined
47 61
  */
48 62
 function onConferenceJoined () {
49
-    for(var i = 0; i < localTracks.length; i++)
50
-    {
51
-        localTracks[i].start();
52
-    }
63
+    console.log("conference joined!");
64
+    room.createLocalTracks().then(onLocalTracks);
53 65
 }
54 66
 
55 67
 function onUserLeft(id) {
@@ -64,8 +76,7 @@ function onUserLeft(id) {
64 76
  * That function is called when connection is established successfully
65 77
  */
66 78
 function onConnectionSuccess(){
67
-    room = connection.initJitsiConference("conference1", confOptions);
68
-    room.createLocalTracks().then(onLocalTracks);
79
+    room = connection.initJitsiConference("conference2", confOptions);
69 80
     room.on(JitsiMeetJS.events.conference.TRACK_ADDED, onRemoteTrack);
70 81
     room.on(JitsiMeetJS.events.conference.TRACK_REMOVED, function () {
71 82
         console.debug("track removed!!!");

+ 1
- 1
doc/example/index.html 查看文件

@@ -12,6 +12,6 @@
12 12
 </head>
13 13
 <body>
14 14
     <video id="localVideo" autoplay="true"></video>
15
-    <audio id="localAudio" autoplay="true"></audio>
15
+    <!--<audio id="localAudio" autoplay="true" muted="true"></audio>-->
16 16
 </body>
17 17
 </html>

+ 56
- 10
lib-jitsi-meet.js 查看文件

@@ -26,6 +26,7 @@ function JitsiConference(options) {
26 26
     this.rtc = new RTC(this.room, options);
27 27
     setupListeners(this);
28 28
     this.participants = {};
29
+    this.lastActiveSpeaker = null;
29 30
 }
30 31
 
31 32
 /**
@@ -220,7 +221,11 @@ function setupListeners(conference) {
220 221
 //        conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_LEFT);
221 222
 //    });
222 223
     conference.rtc.addListener(RTCEvents.DOMINANTSPEAKER_CHANGED, function (id) {
223
-        conference.eventEmitter.emit(JitsiConferenceEvents.ACTIVE_SPEAKER_CHANGED, id);
224
+        if(conference.lastActiveSpeaker !== id && conference.room
225
+            && conference.room.myroomjid !== id) {
226
+            conference.lastActiveSpeaker = id;
227
+            conference.eventEmitter.emit(JitsiConferenceEvents.ACTIVE_SPEAKER_CHANGED, id);
228
+        }
224 229
     });
225 230
 
226 231
     conference.rtc.addListener(RTCEvents.LASTN_CHANGED, function (oldValue, newValue) {
@@ -845,6 +850,7 @@ function JitsiLocalTrack(RTC, stream, eventEmitter, videoType, isGUMStream)
845 850
     this.videoType = videoType;
846 851
     this.isGUMStream = true;
847 852
     this.dontFireRemoveEvent = false;
853
+    this.isStarted = false;
848 854
     var self = this;
849 855
     if(isGUMStream === false)
850 856
         this.isGUMStream = isGUMStream;
@@ -947,6 +953,7 @@ JitsiLocalTrack.prototype.stop = function () {
947 953
  * NOTE: Works for local tracks only.
948 954
  */
949 955
 JitsiLocalTrack.prototype.start = function() {
956
+    this.isStarted = true;
950 957
     this.rtc.room.addStream(this.stream, function () {});
951 958
 }
952 959
 
@@ -1220,7 +1227,6 @@ var DesktopSharingEventTypes
1220 1227
 var MediaStreamType = require("../../service/RTC/MediaStreamTypes");
1221 1228
 var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
1222 1229
 var RTCEvents = require("../../service/RTC/RTCEvents.js");
1223
-var XMPPEvents = require("../../service/xmpp/XMPPEvents");
1224 1230
 var desktopsharing = require("../desktopsharing/desktopsharing");
1225 1231
 
1226 1232
 function getMediaStreamUsage()
@@ -1279,7 +1285,6 @@ function RTC(room, options) {
1279 1285
         if(self.remoteStreams[from])
1280 1286
             self.remoteStreams[from][JitsiTrack.AUDIO].setMute(values.value == "true");
1281 1287
     });
1282
-
1283 1288
 }
1284 1289
 
1285 1290
 /**
@@ -1298,7 +1303,11 @@ RTC.prototype.obtainAudioAndVideoPermissions = function (options, dontCreateJits
1298 1303
 RTC.prototype.onIncommingCall = function(event) {
1299 1304
     if(this.options.config.openSctp)
1300 1305
         this.dataChannels = new DataChannels(event.peerconnection, this.eventEmitter);
1301
-    this.room.addLocalStreams(this.localStreams);
1306
+    for(var i = 0; i < this.localStreams.length; i++)
1307
+        if(this.localStreams[i].isStarted)
1308
+        {
1309
+            this.localStreams[i].start();
1310
+        }
1302 1311
 }
1303 1312
 
1304 1313
 RTC.prototype.selectedEndpoint = function (id) {
@@ -1565,7 +1574,7 @@ RTC.prototype.setDeviceAvailability = function (devices) {
1565 1574
 
1566 1575
 module.exports = RTC;
1567 1576
 
1568
-},{"../../service/RTC/MediaStreamTypes":70,"../../service/RTC/RTCEvents.js":71,"../../service/RTC/StreamEventTypes.js":73,"../../service/desktopsharing/DesktopSharingEventTypes":75,"../../service/xmpp/XMPPEvents":76,"../desktopsharing/desktopsharing":17,"./DataChannels":9,"./JitsiLocalTrack.js":10,"./JitsiRemoteTrack.js":11,"./JitsiTrack":12,"./RTCBrowserType":14,"./RTCUtils.js":15,"events":77}],14:[function(require,module,exports){
1577
+},{"../../service/RTC/MediaStreamTypes":70,"../../service/RTC/RTCEvents.js":71,"../../service/RTC/StreamEventTypes.js":73,"../../service/desktopsharing/DesktopSharingEventTypes":75,"../desktopsharing/desktopsharing":17,"./DataChannels":9,"./JitsiLocalTrack.js":10,"./JitsiRemoteTrack.js":11,"./JitsiTrack":12,"./RTCBrowserType":14,"./RTCUtils.js":15,"events":77}],14:[function(require,module,exports){
1569 1578
 
1570 1579
 var currentBrowser;
1571 1580
 
@@ -4903,6 +4912,7 @@ function JingleSessionPC(me, sid, connection, service) {
4903 4912
     this.removessrc = [];
4904 4913
     this.pendingop = null;
4905 4914
     this.switchstreams = false;
4915
+    this.addingStreams = false;
4906 4916
 
4907 4917
     this.wait = true;
4908 4918
     this.localStreamsSSRC = null;
@@ -4915,6 +4925,7 @@ function JingleSessionPC(me, sid, connection, service) {
4915 4925
      * by the application logic.
4916 4926
      */
4917 4927
     this.videoMuteByUser = false;
4928
+
4918 4929
     this.modifySourcesQueue = async.queue(this._modifySources.bind(this), 1);
4919 4930
     // We start with the queue paused. We resume it when the signaling state is
4920 4931
     // stable and the ice connection state is connected.
@@ -5024,6 +5035,8 @@ JingleSessionPC.prototype.addLocalStreams = function (localStreams) {
5024 5035
     var self = this;
5025 5036
 // add any local and relayed stream
5026 5037
     localStreams.forEach(function(stream) {
5038
+        if(!stream.isStarted())
5039
+            return;
5027 5040
         self.peerconnection.addStream(stream.getOriginalStream());
5028 5041
     });
5029 5042
 }
@@ -5831,7 +5844,8 @@ JingleSessionPC.prototype._modifySources = function (successCallback, queueCallb
5831 5844
     var self = this;
5832 5845
 
5833 5846
     if (this.peerconnection.signalingState == 'closed') return;
5834
-    if (!(this.addssrc.length || this.removessrc.length || this.pendingop !== null || this.switchstreams)){
5847
+    if (!(this.addssrc.length || this.removessrc.length || this.pendingop !== null
5848
+        || this.switchstreams || this.addingStreams)){
5835 5849
         // There is nothing to do since scheduled job might have been executed by another succeeding call
5836 5850
         this.setLocalDescription();
5837 5851
         if(successCallback){
@@ -5841,8 +5855,9 @@ JingleSessionPC.prototype._modifySources = function (successCallback, queueCallb
5841 5855
         return;
5842 5856
     }
5843 5857
 
5844
-    // Reset switch streams flag
5858
+    // Reset switch streams flags
5845 5859
     this.switchstreams = false;
5860
+    this.addingStreams = false;
5846 5861
 
5847 5862
     var sdp = new SDP(this.peerconnection.remoteDescription.sdp);
5848 5863
 
@@ -5991,6 +6006,7 @@ JingleSessionPC.prototype.addStream = function (stream, callback) {
5991 6006
         return;
5992 6007
     }
5993 6008
 
6009
+    this.addingStreams = true;
5994 6010
     this.modifySourcesQueue.push(function() {
5995 6011
         console.log('modify sources done');
5996 6012
 
@@ -6393,6 +6409,7 @@ var RTCBrowserType = require('../RTC/RTCBrowserType');
6393 6409
  */
6394 6410
 var isEnabled = !RTCBrowserType.isFirefox();
6395 6411
 
6412
+
6396 6413
 /**
6397 6414
  * Stored SSRC of local video stream.
6398 6415
  */
@@ -6403,7 +6420,7 @@ var localVideoSSRC;
6403 6420
  * This is in order to tell Chrome what SSRC should be used in RTCP requests
6404 6421
  * instead of 1.
6405 6422
  */
6406
-var localRecvOnlySSRC;
6423
+var localRecvOnlySSRC, localRecvOnlyMSID, localRecvOnlyMSLabel, localRecvOnlyLabel;
6407 6424
 
6408 6425
 /**
6409 6426
  * cname for <tt>localRecvOnlySSRC</tt>
@@ -6475,6 +6492,22 @@ var storeLocalVideoSSRC = function (jingleIq) {
6475 6492
     });
6476 6493
 };
6477 6494
 
6495
+function rangeRandomHex(min, max)
6496
+{
6497
+    return Math.floor(Math.random() * (max - min) + min).toString(16);
6498
+}
6499
+
6500
+var random4digitsHex = rangeRandomHex.bind(null, 4096, 65535);
6501
+var random8digitsHex = rangeRandomHex.bind(null, 268435456, 4294967295);
6502
+var random12digitsHex = rangeRandomHex.bind(null, 17592186044416, 281474976710655);
6503
+
6504
+function generateLabel() {
6505
+    //4294967295 - ffffffff
6506
+    //65535 - ffff
6507
+    //281474976710655 - ffffffffffff
6508
+    return random8digitsHex() + "-" + random4digitsHex() + "-" + random4digitsHex() + "-" + random4digitsHex() + "-" + random12digitsHex();
6509
+}
6510
+
6478 6511
 /**
6479 6512
  * Generates new SSRC for local video recvonly stream.
6480 6513
  * FIXME what about eventual SSRC collision ?
@@ -6485,7 +6518,12 @@ function generateRecvonlySSRC() {
6485 6518
         Math.random().toString(10).substring(2, 11);
6486 6519
     localRecvOnlyCName =
6487 6520
         Math.random().toString(36).substring(2);
6488
-    console.info(
6521
+    localRecvOnlyMSLabel = generateLabel();
6522
+    localRecvOnlyLabel = generateLabel();
6523
+    localRecvOnlyMSID = localRecvOnlyMSLabel + " " + localRecvOnlyLabel;
6524
+
6525
+
6526
+        console.info(
6489 6527
         "Generated local recvonly SSRC: " + localRecvOnlySSRC +
6490 6528
         ", cname: " + localRecvOnlyCName);
6491 6529
 }
@@ -6556,12 +6594,19 @@ var LocalSSRCReplacement = {
6556 6594
                 if (!localRecvOnlySSRC) {
6557 6595
                     generateRecvonlySSRC();
6558 6596
                 }
6597
+                localVideoSSRC = localRecvOnlySSRC;
6559 6598
 
6560 6599
                 console.info('No SSRC in video recvonly stream' +
6561 6600
                              ' - adding SSRC: ' + localRecvOnlySSRC);
6562 6601
 
6563 6602
                 sdp.media[1] += 'a=ssrc:' + localRecvOnlySSRC +
6564
-                                ' cname:' + localRecvOnlyCName + '\r\n';
6603
+                                ' cname:' + localRecvOnlyCName + '\r\n' +
6604
+                                'a=ssrc:' + localRecvOnlySSRC +
6605
+                                ' msid:' + localRecvOnlyMSID + '\r\n' +
6606
+                                'a=ssrc:' + localRecvOnlySSRC +
6607
+                                ' mslabel:' + localRecvOnlyMSLabel + '\r\n' +
6608
+                                'a=ssrc:' + localRecvOnlySSRC +
6609
+                                ' label:' + localRecvOnlyLabel + '\r\n';
6565 6610
 
6566 6611
                 localDescription.sdp = sdp.session + sdp.media.join('');
6567 6612
             }
@@ -7799,6 +7844,7 @@ function TraceablePeerConnection(ice_config, constraints, session) {
7799 7844
 
7800 7845
     // override as desired
7801 7846
     this.trace = function (what, info) {
7847
+        console.debug(what + " - " + info);
7802 7848
         /*console.warn('WTRACE', what, info);
7803 7849
         if (info && RTCBrowserType.isIExplorer()) {
7804 7850
             if (info.length > 1024) {

+ 2
- 0
modules/RTC/JitsiLocalTrack.js 查看文件

@@ -14,6 +14,7 @@ function JitsiLocalTrack(RTC, stream, eventEmitter, videoType, isGUMStream)
14 14
     this.videoType = videoType;
15 15
     this.isGUMStream = true;
16 16
     this.dontFireRemoveEvent = false;
17
+    this.isStarted = false;
17 18
     var self = this;
18 19
     if(isGUMStream === false)
19 20
         this.isGUMStream = isGUMStream;
@@ -116,6 +117,7 @@ JitsiLocalTrack.prototype.stop = function () {
116 117
  * NOTE: Works for local tracks only.
117 118
  */
118 119
 JitsiLocalTrack.prototype.start = function() {
120
+    this.isStarted = true;
119 121
     this.rtc.room.addStream(this.stream, function () {});
120 122
 }
121 123
 

+ 5
- 3
modules/RTC/RTC.js 查看文件

@@ -11,7 +11,6 @@ var DesktopSharingEventTypes
11 11
 var MediaStreamType = require("../../service/RTC/MediaStreamTypes");
12 12
 var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
13 13
 var RTCEvents = require("../../service/RTC/RTCEvents.js");
14
-var XMPPEvents = require("../../service/xmpp/XMPPEvents");
15 14
 var desktopsharing = require("../desktopsharing/desktopsharing");
16 15
 
17 16
 function getMediaStreamUsage()
@@ -70,7 +69,6 @@ function RTC(room, options) {
70 69
         if(self.remoteStreams[from])
71 70
             self.remoteStreams[from][JitsiTrack.AUDIO].setMute(values.value == "true");
72 71
     });
73
-
74 72
 }
75 73
 
76 74
 /**
@@ -89,7 +87,11 @@ RTC.prototype.obtainAudioAndVideoPermissions = function (options, dontCreateJits
89 87
 RTC.prototype.onIncommingCall = function(event) {
90 88
     if(this.options.config.openSctp)
91 89
         this.dataChannels = new DataChannels(event.peerconnection, this.eventEmitter);
92
-    this.room.addLocalStreams(this.localStreams);
90
+    for(var i = 0; i < this.localStreams.length; i++)
91
+        if(this.localStreams[i].isStarted)
92
+        {
93
+            this.localStreams[i].start();
94
+        }
93 95
 }
94 96
 
95 97
 RTC.prototype.selectedEndpoint = function (id) {

+ 9
- 2
modules/xmpp/JingleSessionPC.js 查看文件

@@ -37,6 +37,7 @@ function JingleSessionPC(me, sid, connection, service) {
37 37
     this.removessrc = [];
38 38
     this.pendingop = null;
39 39
     this.switchstreams = false;
40
+    this.addingStreams = false;
40 41
 
41 42
     this.wait = true;
42 43
     this.localStreamsSSRC = null;
@@ -49,6 +50,7 @@ function JingleSessionPC(me, sid, connection, service) {
49 50
      * by the application logic.
50 51
      */
51 52
     this.videoMuteByUser = false;
53
+
52 54
     this.modifySourcesQueue = async.queue(this._modifySources.bind(this), 1);
53 55
     // We start with the queue paused. We resume it when the signaling state is
54 56
     // stable and the ice connection state is connected.
@@ -158,6 +160,8 @@ JingleSessionPC.prototype.addLocalStreams = function (localStreams) {
158 160
     var self = this;
159 161
 // add any local and relayed stream
160 162
     localStreams.forEach(function(stream) {
163
+        if(!stream.isStarted())
164
+            return;
161 165
         self.peerconnection.addStream(stream.getOriginalStream());
162 166
     });
163 167
 }
@@ -965,7 +969,8 @@ JingleSessionPC.prototype._modifySources = function (successCallback, queueCallb
965 969
     var self = this;
966 970
 
967 971
     if (this.peerconnection.signalingState == 'closed') return;
968
-    if (!(this.addssrc.length || this.removessrc.length || this.pendingop !== null || this.switchstreams)){
972
+    if (!(this.addssrc.length || this.removessrc.length || this.pendingop !== null
973
+        || this.switchstreams || this.addingStreams)){
969 974
         // There is nothing to do since scheduled job might have been executed by another succeeding call
970 975
         this.setLocalDescription();
971 976
         if(successCallback){
@@ -975,8 +980,9 @@ JingleSessionPC.prototype._modifySources = function (successCallback, queueCallb
975 980
         return;
976 981
     }
977 982
 
978
-    // Reset switch streams flag
983
+    // Reset switch streams flags
979 984
     this.switchstreams = false;
985
+    this.addingStreams = false;
980 986
 
981 987
     var sdp = new SDP(this.peerconnection.remoteDescription.sdp);
982 988
 
@@ -1125,6 +1131,7 @@ JingleSessionPC.prototype.addStream = function (stream, callback) {
1125 1131
         return;
1126 1132
     }
1127 1133
 
1134
+    this.addingStreams = true;
1128 1135
     this.modifySourcesQueue.push(function() {
1129 1136
         console.log('modify sources done');
1130 1137
 

+ 52
- 6
modules/xmpp/LocalSSRCReplacement.js 查看文件

@@ -41,17 +41,18 @@ var RTCBrowserType = require('../RTC/RTCBrowserType');
41 41
  */
42 42
 var isEnabled = !RTCBrowserType.isFirefox();
43 43
 
44
+
44 45
 /**
45 46
  * Stored SSRC of local video stream.
46 47
  */
47 48
 var localVideoSSRC;
48 49
 
49 50
 /**
50
- * SSRC used for recvonly video stream when we have no local camera.
51
+ * SSRC, msid, mslabel, label used for recvonly video stream when we have no local camera.
51 52
  * This is in order to tell Chrome what SSRC should be used in RTCP requests
52 53
  * instead of 1.
53 54
  */
54
-var localRecvOnlySSRC;
55
+var localRecvOnlySSRC, localRecvOnlyMSID, localRecvOnlyMSLabel, localRecvOnlyLabel;
55 56
 
56 57
 /**
57 58
  * cname for <tt>localRecvOnlySSRC</tt>
@@ -124,16 +125,54 @@ var storeLocalVideoSSRC = function (jingleIq) {
124 125
 };
125 126
 
126 127
 /**
127
- * Generates new SSRC for local video recvonly stream.
128
+ * Generates random hex number within the range [min, max]
129
+ * @param max the maximum value for the generated number
130
+ * @param min the minimum value for the generated number
131
+ * @returns random hex number
132
+ */
133
+function rangeRandomHex(min, max)
134
+{
135
+    return Math.floor(Math.random() * (max - min) + min).toString(16);
136
+}
137
+
138
+/**
139
+ * Generates hex number with length 4
140
+ */
141
+var random4digitsHex = rangeRandomHex.bind(null, 4096, 65535);
142
+
143
+/**
144
+ * Generates hex number with length 8
145
+ */
146
+var random8digitsHex = rangeRandomHex.bind(null, 268435456, 4294967295);
147
+
148
+/**
149
+ * Generates hex number with length 12
150
+ */
151
+var random12digitsHex = rangeRandomHex.bind(null, 17592186044416, 281474976710655);
152
+
153
+/**
154
+ * Generates new label/mslabel attribute
155
+ * @returns {string} label/mslabel attribute
156
+ */
157
+function generateLabel() {
158
+    return random8digitsHex() + "-" + random4digitsHex() + "-" + random4digitsHex() + "-" + random4digitsHex() + "-" + random12digitsHex();
159
+}
160
+
161
+/**
162
+ * Generates new SSRC, CNAME, mslabel, label and msid for local video recvonly stream.
128 163
  * FIXME what about eventual SSRC collision ?
129 164
  */
130 165
 function generateRecvonlySSRC() {
131
-    //
132 166
     localRecvOnlySSRC =
133 167
         Math.random().toString(10).substring(2, 11);
134 168
     localRecvOnlyCName =
135 169
         Math.random().toString(36).substring(2);
136
-    console.info(
170
+    localRecvOnlyMSLabel = generateLabel();
171
+    localRecvOnlyLabel = generateLabel();
172
+    localRecvOnlyMSID = localRecvOnlyMSLabel + " " + localRecvOnlyLabel;
173
+
174
+
175
+        console.info(
137 176
         "Generated local recvonly SSRC: " + localRecvOnlySSRC +
138 177
         ", cname: " + localRecvOnlyCName);
139 178
 }
@@ -204,12 +243,19 @@ var LocalSSRCReplacement = {
204 243
                 if (!localRecvOnlySSRC) {
205 244
                     generateRecvonlySSRC();
206 245
                 }
246
+                localVideoSSRC = localRecvOnlySSRC;
207 247
 
208 248
                 console.info('No SSRC in video recvonly stream' +
209 249
                              ' - adding SSRC: ' + localRecvOnlySSRC);
210 250
 
211 251
                 sdp.media[1] += 'a=ssrc:' + localRecvOnlySSRC +
212
-                                ' cname:' + localRecvOnlyCName + '\r\n';
252
+                                ' cname:' + localRecvOnlyCName + '\r\n' +
253
+                                'a=ssrc:' + localRecvOnlySSRC +
254
+                                ' msid:' + localRecvOnlyMSID + '\r\n' +
255
+                                'a=ssrc:' + localRecvOnlySSRC +
256
+                                ' mslabel:' + localRecvOnlyMSLabel + '\r\n' +
257
+                                'a=ssrc:' + localRecvOnlySSRC +
258
+                                ' label:' + localRecvOnlyLabel + '\r\n';
213 259
 
214 260
                 localDescription.sdp = sdp.session + sdp.media.join('');
215 261
             }

正在加载...
取消
保存