Skip to content

Commit

Permalink
ref(xmpp) translate unified-plan SDP->Jingle directly.
Browse files Browse the repository at this point in the history
Without having to run it through the SDPInterop.toPlanB cycle.
  • Loading branch information
jallamsetty1 committed Sep 25, 2024
1 parent f770964 commit d4e058e
Show file tree
Hide file tree
Showing 5 changed files with 966 additions and 41 deletions.
11 changes: 3 additions & 8 deletions modules/RTC/TraceablePeerConnection.js
Original file line number Diff line number Diff line change
Expand Up @@ -1322,9 +1322,6 @@ const getters = {

// For a jvb connection, transform the SDP to Plan B first.
if (!this.isP2P) {
desc = this.interop.toPlanB(desc);
this.trace('getLocalDescription::postTransform (Plan B)', dumpSDP(desc));

desc = this._injectSsrcGroupForUnifiedSimulcast(desc);
this.trace('getLocalDescription::postTransform (inject ssrc group)', dumpSDP(desc));
}
Expand Down Expand Up @@ -1643,7 +1640,7 @@ TraceablePeerConnection.prototype.getConfiguredVideoCodec = function(localTrack)
* @returns {Array}
*/
TraceablePeerConnection.prototype.getConfiguredVideoCodecs = function(description) {
const currentSdp = description?.sdp ?? this.peerconnection.localDescription?.sdp;
const currentSdp = description?.sdp ?? this.localDescription?.sdp;

if (!currentSdp) {
return [];
Expand Down Expand Up @@ -1746,7 +1743,7 @@ TraceablePeerConnection.prototype.findSenderForTrack = function(track) {
* @returns {void}
*/
TraceablePeerConnection.prototype.processLocalSdpForTransceiverInfo = function(localTracks) {
const localSdp = this.peerconnection.localDescription?.sdp;
const localSdp = this.localDescription?.sdp;

if (!localSdp) {
return;
Expand Down Expand Up @@ -2599,9 +2596,7 @@ TraceablePeerConnection.prototype.createOffer = function(constraints) {
return this._createOfferOrAnswer(true /* offer */, constraints);
};

TraceablePeerConnection.prototype._createOfferOrAnswer = function(
isOffer,
constraints) {
TraceablePeerConnection.prototype._createOfferOrAnswer = function(isOffer, constraints) {
const logName = isOffer ? 'Offer' : 'Answer';

this.trace(`create${logName}`, JSON.stringify(constraints, null, ' '));
Expand Down
105 changes: 86 additions & 19 deletions modules/sdp/SDP.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import $ from 'jquery';
import { cloneDeep } from 'lodash-es';
import transform from 'sdp-transform';
import { Strophe } from 'strophe.js';

import { MediaDirection } from '../../service/RTC/MediaDirection';
import { MediaType } from '../../service/RTC/MediaType';
Expand All @@ -20,8 +21,9 @@ export default class SDP {
*
* @param {string} sdp - The SDP generated by the browser when SDP->Jingle conversion is needed, an empty string
* when Jingle->SDP conversion is needed.
* @param {boolean} isP2P - Whether this SDP belongs to a p2p peerconnection.
*/
constructor(sdp) {
constructor(sdp, isP2P = false) {
const media = sdp.split('\r\nm=');

for (let i = 1, length = media.length; i < length; i++) {
Expand All @@ -34,6 +36,7 @@ export default class SDP {
}
const session = `${media.shift()}\r\n`;

this.isP2P = isP2P;
this.media = media;
this.raw = session + media.join('');
this.session = session;
Expand Down Expand Up @@ -446,16 +449,21 @@ export default class SDP {
xmlns: XEP.BUNDLE_MEDIA,
semantics
});
parts.forEach(part => elem.c('content', { name: part }).up());

// Bundle all the media types. Jicofo expects the 'application' media type to be signaled as 'data'.
let mediaTypes = [ MediaType.AUDIO, MediaType.VIDEO, 'data' ];

// For p2p connection, 'mid' will be used in the bundle group.
if (this.isP2P) {
mediaTypes = this.media.map(mediaItem => SDPUtil.parseMID(SDPUtil.findLine(mediaItem, 'a=mid:')));
}
mediaTypes.forEach(type => elem.c('content', { name: type }).up());
elem.up();
});

this.media.forEach((mediaItem, i) => {
const mline = SDPUtil.parseMLine(mediaItem.split('\r\n')[0]);

if (![ MediaType.AUDIO, MediaType.VIDEO, MediaType.APPLICATION ].includes(mline.media)) {
return;
}
const mediaType = mline.media === MediaType.APPLICATION ? 'data' : mline.media;

let ssrc = false;
const assrcline = SDPUtil.findLine(mediaItem, 'a=ssrc:');
Expand All @@ -464,32 +472,91 @@ export default class SDP {
ssrc = assrcline.substring(7).split(' ')[0];
}

const contents = $(elem.tree()).find(`content[name='${mediaType}']`);

// Append source groups from the new m-lines to the existing media description. The SDP will have multiple
// m-lines for audio and video including the recv-only ones for remote sources but there needs to be only
// one media description for a given media type that should include all the sources, i.e., both the camera
// and screenshare sources should be added to the 'video' description.
for (const content of contents) {
if (!content.hasAttribute('creator')) {
// eslint-disable-next-line no-continue
continue;
}

if (ssrc) {
const description = $(content).find('description');
const ssrcMap = SDPUtil.parseSSRC(mediaItem);

for (const [ availableSsrc, ssrcParameters ] of ssrcMap) {
const sourceName = SDPUtil.parseSourceNameLine(ssrcParameters);
const videoType = SDPUtil.parseVideoTypeLine(ssrcParameters);
const source = Strophe.xmlElement('source', {
ssrc: availableSsrc,
name: sourceName,
videoType,
xmlns: XEP.SOURCE_ATTRIBUTES
});

const msid = SDPUtil.parseMSIDAttribute(ssrcParameters);

if (msid) {
const param = Strophe.xmlElement('parameter', {
name: 'msid',
value: msid
});

source.append(param);
}
description.append(source);
}

const ssrcGroupLines = SDPUtil.findLines(mediaItem, 'a=ssrc-group:');

ssrcGroupLines.forEach(line => {
const idx = line.indexOf(' ');
const semantics = line.substr(0, idx).substr(13);
const ssrcs = line.substr(14 + semantics.length).split(' ');

if (ssrcs.length) {
const group = Strophe.xmlElement('ssrc-group', {
semantics,
xmlns: XEP.SOURCE_ATTRIBUTES
});

for (const val of ssrcs) {
const src = Strophe.xmlElement('source', {
ssrc: val
});

group.append(src);
}
description.append(group);
}
});
}

return;
}
const mid = SDPUtil.parseMID(SDPUtil.findLine(mediaItem, 'a=mid:'));

elem.c('content', {
creator: thecreator,
name: mline.media
name: this.isP2P ? mid : mediaType
});
const amidline = SDPUtil.findLine(mediaItem, 'a=mid:');

if (amidline) {
// Prefer identifier from a=mid if present.
elem.attrs({ name: SDPUtil.parseMID(amidline) });
}

if (mline.media === MediaType.VIDEO && typeof this.initialLastN === 'number') {
if (mediaType === MediaType.VIDEO && typeof this.initialLastN === 'number') {
elem.c('initial-last-n', {
xmlns: 'jitsi:colibri2',
value: this.initialLastN
}).up();
}

if ([ MediaType.AUDIO, MediaType.VIDEO ].includes(mline.media)) {
if ([ MediaType.AUDIO, MediaType.VIDEO ].includes(mediaType)) {
elem.c('description', {
xmlns: XEP.RTP_MEDIA,
media: mline.media
media: mediaType
});
if (ssrc) {
elem.attrs({ ssrc });
}

mline.fmt.forEach(format => {
const rtpmap = SDPUtil.findLine(mediaItem, `a=rtpmap:${format}`);
Expand Down
Loading

0 comments on commit d4e058e

Please sign in to comment.