From 38356a0084fad3285143ddee1ffa5e88362eb546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Birm=C3=A9?= Date: Fri, 28 Jun 2024 21:19:53 +0200 Subject: [PATCH] feat: wip whip connection established --- src/api_productions_core_functions.ts | 82 ++++++--------------- src/api_whip.ts | 1 + src/connection.ts | 100 +++++++++++--------------- 3 files changed, 65 insertions(+), 118 deletions(-) diff --git a/src/api_productions_core_functions.ts b/src/api_productions_core_functions.ts index 44bcac1..1458165 100644 --- a/src/api_productions_core_functions.ts +++ b/src/api_productions_core_functions.ts @@ -110,73 +110,35 @@ export class CoreFunctions { endpointId ); + const parsedOffer = parse(offer); const answer: SessionDescription = connection.createAnswer(offer); const sdpAnswer: string = write(answer); if (sdpAnswer) { - const answerMediaDescription = answer.media[0]; - if (!answerMediaDescription) { - throw new Error( - 'Missing audio media description when handling SDP answer from offer' - ); - } - if (answer.media[1].ssrcs) { - let parsedSsrcs = answer.media[1].ssrcs[0].id; - if (typeof parsedSsrcs === 'string') { - parsedSsrcs = parseInt(parsedSsrcs, 10); + for (const media of parsedOffer.media) { + if (media.type === 'audio') { + endpointDescription.audio.ssrcs = []; + media.ssrcs && + media.ssrcs + .filter((ssrcs) => ssrcs.attribute === 'msid') + .forEach((ssrcs) => + endpointDescription.audio.ssrcs.push(parseInt(`${ssrcs.id}`)) + ); } - endpointDescription.audio.ssrcs.push(parsedSsrcs); - } - if (endpointDescription.audio.ssrcs.length === 0) { - throw new Error( - 'Missing audio ssrcs when handling SDP answer from offer' - ); - } - const transport = endpointDescription['bundle-transport']; - if (!transport) { - throw new Error( - 'Missing endpointDescription when handling SDP answer from offer' - ); - } - if (!transport.dtls) { - throw new Error('Missing dtls when handling SDP answer from offer'); } - if (!transport.ice) { - throw new Error('Missing ice when handling SDP answer from offer'); - } - const answerFingerprint = answer.fingerprint - ? answer.fingerprint - : answerMediaDescription.fingerprint; - if (!answerFingerprint) { - throw new Error( - 'Missing answerFingerprint when handling sdp answer from endpoint' - ); + for (const media of answer.media) { + if (media.type === 'audio') { + endpointDescription.audio['payload-type'].id = media.rtp[0].payload; + endpointDescription.audio['rtp-hdrexts'] = []; + media.ext && + media.ext.forEach((ext: any) => + endpointDescription.audio['rtp-hdrexts'].push({ + id: ext.value, + uri: ext.uri + }) + ); + } } - transport.dtls.type = answerFingerprint.type; - transport.dtls.hash = answerFingerprint.hash; - transport.dtls.setup = answerMediaDescription.setup || ''; - transport.ice.ufrag = this.toStringIfNumber( - answerMediaDescription.iceUfrag - ); - transport.ice.pwd = answerMediaDescription.icePwd || ''; - transport.ice.candidates = !answerMediaDescription.candidates - ? [] - : answerMediaDescription.candidates.flatMap((element) => { - return { - generation: element.generation ? element.generation : 0, - component: element.component, - protocol: element.transport.toLowerCase(), - port: element.port, - ip: element.ip, - relPort: element.rport, - relAddr: element.raddr, - foundation: element.foundation.toString(), - priority: parseInt(element.priority.toString(), 10), - type: element.type, - network: element['network-id'] - }; - }); - // Configure endpoint await smb.configureEndpoint( smbServerUrl, diff --git a/src/api_whip.ts b/src/api_whip.ts index e775bfe..b5efaf1 100644 --- a/src/api_whip.ts +++ b/src/api_whip.ts @@ -115,6 +115,7 @@ const apiWhip: FastifyPluginCallback = ( }); reply.code(201).send(sdpAnswer); } catch (err) { + console.error(err); reply.code(500).send({ message: 'Unhandled error: ' + err }); } } diff --git a/src/connection.ts b/src/connection.ts index 217af94..7b79611 100644 --- a/src/connection.ts +++ b/src/connection.ts @@ -102,9 +102,6 @@ export class Connection { if (!this.endpointDescription['bundle-transport']) { throw new Error('Missing bundle-transport in endpointDescription'); } - if (!this.mediaStreams) { - throw new Error('Missing endpointDescription audio'); - } const transport = this.endpointDescription['bundle-transport']; @@ -116,16 +113,14 @@ export class Connection { } const parsedSDP = parse(offer); - parsedSDP.origin && parsedSDP.origin.sessionVersion++; + console.log('Offer received: ', inspect(parsedSDP, { depth: null })); - // We are only interested in audio now - parsedSDP.media = parsedSDP.media.filter((media) => media.type == 'audio'); + parsedSDP.origin && parsedSDP.origin.sessionVersion++; - let mediaStreamIdx = 0; let bundleGroupMids = ''; + let candidatesAdded = false; for (const media of parsedSDP.media) { - const mediaStreamSsrc = this.mediaStreams.audio.ssrcs[mediaStreamIdx]; bundleGroupMids = bundleGroupMids === '' ? `${media.mid}` @@ -139,7 +134,6 @@ export class Connection { }; media.setup = media.setup === 'actpass' ? 'active' : 'actpass'; media.ssrcGroups = []; - media.ssrcs = []; media.msid = undefined; media.port = 9; media.rtcp = { @@ -148,60 +142,50 @@ export class Connection { ipVer: 4, address: '0.0.0.0' }; - media.ssrcs.push({ - id: mediaStreamSsrc.ssrc, - attribute: 'cname', - value: mediaStreamSsrc.cname - }); - media.ssrcs.push({ - id: mediaStreamSsrc.ssrc, - attribute: 'label', - value: mediaStreamSsrc.label - }); - media.ssrcs.push({ - id: mediaStreamSsrc.ssrc, - attribute: 'mslabel', - value: mediaStreamSsrc.mslabel - }); - media.ssrcs.push({ - id: mediaStreamSsrc.ssrc, - attribute: 'msid', - value: `${mediaStreamSsrc.mslabel} ${mediaStreamSsrc.label}` - }); - media.candidates = transport.ice.candidates.map((element) => { - return { - foundation: element.foundation, - component: element.component, - transport: element.protocol, - priority: element.priority, - ip: element.ip, - port: element.port, - type: element.type, - raddr: element['rel-addr'], - rport: element['rel-port'], - generation: element.generation, - 'network-id': element.network - }; - }); + media.ssrcs = []; + if (!candidatesAdded) { + media.candidates = transport.ice.candidates.map((element) => { + return { + foundation: element.foundation, + component: element.component, + transport: element.protocol, + priority: element.priority, + ip: element.ip, + port: element.port, + type: element.type, + raddr: element['rel-addr'], + rport: element['rel-port'], + generation: element.generation, + 'network-id': element.network + }; + }); + candidatesAdded = true; + } media.connection = { version: 4, ip: '0.0.0.0' }; - media.rtp = media.rtp.filter((rtp) => rtp.codec.toLowerCase() === 'opus'); - const opusPayloadType = media.rtp.at(0)?.payload; - media.fmtp = media.fmtp.filter( - (fmtp) => fmtp.payload === opusPayloadType - ); - media.payloads = `${opusPayloadType}`; - media.direction = 'recvonly'; - media.rtcpFb = undefined; - media.ext = this.endpointDescription.audio['rtp-hdrexts'].flatMap( - (element) => { - return { value: element.id, uri: element.uri }; - } - ); - mediaStreamIdx++; + if (media.type === 'audio') { + media.rtp = media.rtp.filter( + (rtp) => rtp.codec.toLowerCase() === 'opus' + ); + const opusPayloadType = media.rtp.at(0)?.payload; + media.fmtp = media.fmtp.filter( + (fmtp) => fmtp.payload === opusPayloadType + ); + media.payloads = `${opusPayloadType}`; + media.direction = 'recvonly'; + media.rtcpFb = undefined; + media.ext = + media.ext && + media.ext.filter( + (ext) => + ext.uri === 'urn:ietf:params:rtp-hdrext:ssrc-audio-level' || + ext.uri === + 'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time' + ); + } } parsedSDP.groups = [ {