Skip to content

Commit c2b7734

Browse files
committed
Merge pull request #271 from fippo/encparams
use RTCRtpEncodingParameters in Edge
2 parents 8a53198 + e243342 commit c2b7734

File tree

3 files changed

+171
-26
lines changed

3 files changed

+171
-26
lines changed

src/js/edge/edge_sdp.js

+77-4
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ SDPUtils.writeRtcpFb = function(codec) {
216216
SDPUtils.parseSsrcMedia = function(line) {
217217
var sp = line.indexOf(' ');
218218
var parts = {
219-
ssrc: line.substr(7, sp - 7)
219+
ssrc: parseInt(line.substr(7, sp - 7), 10)
220220
};
221221
var colon = line.indexOf(':', sp);
222222
if (colon > -1) {
@@ -353,6 +353,78 @@ SDPUtils.writeRtpDescription = function(kind, caps) {
353353
return sdp;
354354
};
355355

356+
// Parses the SDP media section and returns an array of
357+
// RTCRtpEncodingParameters.
358+
SDPUtils.parseRtpEncodingParameters = function(mediaSection) {
359+
var encodingParameters = [];
360+
var description = SDPUtils.parseRtpParameters(mediaSection);
361+
var hasRed = description.fecMechanisms.indexOf('RED') !== -1;
362+
var hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1;
363+
364+
// filter a=ssrc:... cname:, ignore PlanB-msid
365+
var ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')
366+
.map(function(line) {
367+
return SDPUtils.parseSsrcMedia(line);
368+
})
369+
.filter(function(parts) {
370+
return parts.attribute === 'cname';
371+
});
372+
var primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc;
373+
var secondarySsrc;
374+
375+
var flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID')
376+
.map(function(line) {
377+
var parts = line.split(' ');
378+
parts.shift();
379+
return parts.map(function(part) {
380+
return parseInt(part, 10);
381+
});
382+
});
383+
if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) {
384+
secondarySsrc = flows[0][1];
385+
}
386+
387+
description.codecs.forEach(function(codec) {
388+
if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) {
389+
var encParam = {
390+
ssrc: primarySsrc,
391+
codecPayloadType: parseInt(codec.parameters.apt, 10),
392+
rtx: {
393+
ssrc: secondarySsrc
394+
}
395+
};
396+
encodingParameters.push(encParam);
397+
if (hasRed) {
398+
encParam = JSON.parse(JSON.stringify(encParam));
399+
encParam.fec = {
400+
ssrc: secondarySsrc,
401+
mechanism: hasUlpfec ? 'red+ulpfec' : 'red'
402+
};
403+
encodingParameters.push(encParam);
404+
}
405+
}
406+
});
407+
if (encodingParameters.length === 0 && primarySsrc) {
408+
encodingParameters.push({
409+
ssrc: primarySsrc
410+
});
411+
}
412+
413+
// we support both b=AS and b=TIAS but interpret AS as TIAS.
414+
var bandwidth = SDPUtils.matchPrefix(mediaSection, 'b=');
415+
if (bandwidth.length) {
416+
if (bandwidth[0].indexOf('b=TIAS:') === 0) {
417+
bandwidth = parseInt(bandwidth[0].substr(7), 10);
418+
} else if (bandwidth[0].indexOf('b=AS:') === 0) {
419+
bandwidth = parseInt(bandwidth[0].substr(5), 10);
420+
}
421+
encodingParameters.forEach(function(params) {
422+
params.maxBitrate = bandwidth;
423+
});
424+
}
425+
return encodingParameters;
426+
};
427+
356428
SDPUtils.writeSessionBoilerplate = function() {
357429
// FIXME: sess-id should be an NTP timestamp.
358430
return 'v=0\r\n' +
@@ -390,11 +462,12 @@ SDPUtils.writeMediaSection = function(transceiver, caps, type, stream) {
390462
var msid = 'msid:' + stream.id + ' ' +
391463
transceiver.rtpSender.track.id + '\r\n';
392464
sdp += 'a=' + msid;
393-
sdp += 'a=ssrc:' + transceiver.sendSsrc + ' ' + msid;
465+
sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc +
466+
' ' + msid;
394467
}
395468
// FIXME: this should be written by writeRtpDescription.
396-
sdp += 'a=ssrc:' + transceiver.sendSsrc + ' cname:' +
397-
SDPUtils.localCName + '\r\n';
469+
sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc +
470+
' cname:' + SDPUtils.localCName + '\r\n';
398471
return sdp;
399472
};
400473

src/js/edge/edge_shim.js

+28-22
Original file line numberDiff line numberDiff line change
@@ -301,23 +301,23 @@ var edgeShim = {
301301
var params = this._getCommonCapabilities(transceiver.localCapabilities,
302302
transceiver.remoteCapabilities);
303303
if (send && transceiver.rtpSender) {
304-
params.encodings = [{
305-
ssrc: transceiver.sendSsrc
306-
}];
304+
params.encodings = transceiver.sendEncodingParameters;
307305
params.rtcp = {
308-
cname: SDPUtils.localCName,
309-
ssrc: transceiver.recvSsrc
306+
cname: SDPUtils.localCName
310307
};
308+
if (transceiver.recvEncodingParameters.length) {
309+
params.rtcp.ssrc = transceiver.recvEncodingParameters[0].ssrc;
310+
}
311311
transceiver.rtpSender.send(params);
312312
}
313313
if (recv && transceiver.rtpReceiver) {
314-
params.encodings = [{
315-
ssrc: transceiver.recvSsrc
316-
}];
314+
params.encodings = transceiver.recvEncodingParameters;
317315
params.rtcp = {
318-
cname: transceiver.cname,
319-
ssrc: transceiver.sendSsrc
316+
cname: transceiver.cname
320317
};
318+
if (transceiver.sendEncodingParameters.length) {
319+
params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc;
320+
}
321321
transceiver.rtpReceiver.receive(params);
322322
}
323323
};
@@ -443,8 +443,8 @@ var edgeShim = {
443443
var dtlsTransport;
444444
var rtpSender;
445445
var rtpReceiver;
446-
var sendSsrc;
447-
var recvSsrc;
446+
var sendEncodingParameters;
447+
var recvEncodingParameters;
448448
var localCapabilities;
449449

450450
var track;
@@ -458,6 +458,9 @@ var edgeShim = {
458458
remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection,
459459
sessionpart);
460460
}
461+
recvEncodingParameters =
462+
SDPUtils.parseRtpEncodingParameters(mediaSection);
463+
461464
var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:');
462465
if (mid.length) {
463466
mid = mid[0].substr(6);
@@ -476,7 +479,6 @@ var edgeShim = {
476479
return obj.attribute === 'cname';
477480
})[0];
478481
if (remoteSsrc) {
479-
recvSsrc = parseInt(remoteSsrc.ssrc, 10);
480482
cname = remoteSsrc.value;
481483
}
482484

@@ -497,7 +499,9 @@ var edgeShim = {
497499
}
498500

499501
localCapabilities = RTCRtpReceiver.getCapabilities(kind);
500-
sendSsrc = (2 * sdpMLineIndex + 2) * 1001;
502+
sendEncodingParameters = [{
503+
ssrc: (2 * sdpMLineIndex + 2) * 1001
504+
}];
501505

502506
rtpReceiver = new RTCRtpReceiver(transports.dtlsTransport, kind);
503507

@@ -528,8 +532,8 @@ var edgeShim = {
528532
kind: kind,
529533
mid: mid,
530534
cname: cname,
531-
sendSsrc: sendSsrc,
532-
recvSsrc: recvSsrc
535+
sendEncodingParameters: sendEncodingParameters,
536+
recvEncodingParameters: recvEncodingParameters
533537
};
534538
// Start the RTCRtpReceiver now. The RTPSender is started in
535539
// setLocalDescription.
@@ -543,11 +547,11 @@ var edgeShim = {
543547
dtlsTransport = transceiver.dtlsTransport;
544548
rtpSender = transceiver.rtpSender;
545549
rtpReceiver = transceiver.rtpReceiver;
546-
sendSsrc = transceiver.sendSsrc;
547-
// recvSsrc = transceiver.recvSsrc;
550+
sendEncodingParameters = transceiver.sendEncodingParameters;
548551
localCapabilities = transceiver.localCapabilities;
549552

550-
self.transceivers[sdpMLineIndex].recvSsrc = recvSsrc;
553+
self.transceivers[sdpMLineIndex].recvEncodingParameters =
554+
recvEncodingParameters;
551555
self.transceivers[sdpMLineIndex].remoteCapabilities =
552556
remoteCapabilities;
553557
self.transceivers[sdpMLineIndex].cname = cname;
@@ -797,7 +801,9 @@ var edgeShim = {
797801
var rtpReceiver;
798802

799803
// generate an ssrc now, to be used later in rtpSender.send
800-
var sendSsrc = (2 * sdpMLineIndex + 1) * 1001;
804+
var sendEncodingParameters = [{
805+
ssrc: (2 * sdpMLineIndex + 1) * 1001
806+
}];
801807
if (track) {
802808
rtpSender = new RTCRtpSender(track, transports.dtlsTransport);
803809
}
@@ -816,8 +822,8 @@ var edgeShim = {
816822
rtpReceiver: rtpReceiver,
817823
kind: kind,
818824
mid: mid,
819-
sendSsrc: sendSsrc,
820-
recvSsrc: null
825+
sendEncodingParameters: sendEncodingParameters,
826+
recvEncodingParameters: null
821827
};
822828
var transceiver = transceivers[sdpMLineIndex];
823829
sdp += SDPUtils.writeMediaSection(transceiver,

test/sdp.js

+66
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,31 @@ var videoSDP =
4949
'a=ssrc:2715962409 mslabel:EZVtYL50wdbfttMdmVFITVoKc4XgA0KBZXzd\r\n' +
5050
'a=ssrc:2715962409 label:63238d63-9a20-4afc-832c-48678926afce\r\n';
5151

52+
// Firefox offer
53+
var videoSDP2 =
54+
'v=0\r\n' +
55+
'o=mozilla...THIS_IS_SDPARTA-45.0 5508396880163053452 0 IN IP4 0.0.0.0\r\n' +
56+
's=-\r\nt=0 0\r\n' +
57+
'a=fingerprint:sha-256 CC:0D:FB:A8:9F:59:36:57:69:F6:2C:0E:A3:EA:19:5A:E0' +
58+
':D4:37:82:D4:7B:FB:94:3D:F6:0E:F8:29:A7:9E:9C\r\n' +
59+
'a=ice-options:trickle\r\na=msid-semantic:WMS *\r\n' +
60+
'm=video 9 UDP/TLS/RTP/SAVPF 120 126 97\r\n' +
61+
'c=IN IP4 0.0.0.0\r\na=sendrecv\r\n' +
62+
'a=fmtp:126 profile-level-id=42e01f;level-asymmetry-allowed=1;' +
63+
'packetization-mode=1\r\n' +
64+
'a=fmtp:97 profile-level-id=42e01f;level-asymmetry-allowed=1\r\n' +
65+
'a=fmtp:120 max-fs=12288;max-fr=60\r\n' +
66+
'a=ice-pwd:e81aeca45422c37aeb669274d8959200\r\n' +
67+
'a=ice-ufrag:30607a5c\r\na=mid:sdparta_0\r\n' +
68+
'a=msid:{782ddf65-d10e-4dad-80b9-27e9f3928d82} ' +
69+
'{37802bbd-01e2-481e-a2e8-acb5423b7a55}\r\n' +
70+
'a=rtcp-fb:120 nack\r\na=rtcp-fb:120 nack pli\r\na=rtcp-fb:120 ccm fir\r\n' +
71+
'a=rtcp-fb:126 nack\r\na=rtcp-fb:126 nack pli\r\na=rtcp-fb:126 ccm fir\r\n' +
72+
'a=rtcp-fb:97 nack\r\na=rtcp-fb:97 nack pli\r\na=rtcp-fb:97 ccm fir\r\n' +
73+
'a=rtcp-mux\r\na=rtpmap:120 VP8/90000\r\na=rtpmap:126 H264/90000\r\n' +
74+
'a=rtpmap:97 H264/90000\r\na=setup:actpass\r\n' +
75+
'a=ssrc:98927270 cname:{0817e909-53be-4a3f-ac45-b5a0e5edc3a7}\r\n';
76+
5277
test('splitSections', function(t) {
5378
var parsed = SDPUtils.splitSections(videoSDP.replace(/\r\n/g, '\n'));
5479
t.ok(parsed.length === 2,
@@ -114,3 +139,44 @@ test('rtpmap parsing and serialization', function(t) {
114139

115140
t.end();
116141
});
142+
143+
test('parseRtpEncodingParameters', function(t) {
144+
var sections = SDPUtils.splitSections(videoSDP);
145+
var data = SDPUtils.parseRtpEncodingParameters(sections[1]);
146+
t.ok(data.length === 8, 'parsed encoding parameters for four codecs');
147+
148+
t.ok(data[0].ssrc === 1734522595, 'parsed primary SSRC');
149+
t.ok(data[0].rtx, 'has RTX encoding');
150+
t.ok(data[0].rtx.ssrc === 2715962409, 'parsed secondary SSRC for RTX');
151+
t.end();
152+
});
153+
154+
test('parseRtpEncodingParameters fallback', function(t) {
155+
var sections = SDPUtils.splitSections(videoSDP2);
156+
var data = SDPUtils.parseRtpEncodingParameters(sections[1]);
157+
158+
t.ok(data.length === 1 && data[0].ssrc === 98927270, 'parsed single SSRC');
159+
t.end();
160+
});
161+
162+
test('parseRtpEncodingParameters with b=AS', function(t) {
163+
var sections = SDPUtils.splitSections(
164+
videoSDP.replace('c=IN IP4 0.0.0.0\r\n',
165+
'c=IN IP4 0.0.0.0\r\nb=AS:512\r\n')
166+
);
167+
var data = SDPUtils.parseRtpEncodingParameters(sections[1]);
168+
169+
t.ok(data[0].maxBitrate === 512, 'parsed b=AS:512');
170+
t.end();
171+
});
172+
173+
test('parseRtpEncodingParameters with b=TIAS', function(t) {
174+
var sections = SDPUtils.splitSections(
175+
videoSDP.replace('c=IN IP4 0.0.0.0\r\n',
176+
'c=IN IP4 0.0.0.0\r\nb=TIAS:512\r\n')
177+
);
178+
var data = SDPUtils.parseRtpEncodingParameters(sections[1]);
179+
180+
t.ok(data[1].maxBitrate === 512, 'parsed b=AS:512');
181+
t.end();
182+
});

0 commit comments

Comments
 (0)