-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add retainCodecs and retainCandidates functions (#18)
* feat: add filterCodecs and filterCandidates functions * chore: rename filter functions * chore: update unit test descriptions --------- Co-authored-by: Bryce Tham <[email protected]>
- Loading branch information
Showing
5 changed files
with
428 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import * as fs from 'fs'; | ||
import { AvMediaDescription, CodecInfo, Sdp } from './model'; | ||
import { removeCodec, retainCandidates, retainCodecs } from './munge'; | ||
import { parse } from './parser'; | ||
|
||
/** | ||
* Validate that the sdp offer does not use any video codecs besides h264 or opus. | ||
* | ||
* @param offer - The sdp offer string to validate. | ||
* @returns True if the offer is valid. | ||
*/ | ||
const validateOfferCodecs = (offer: Sdp): boolean => { | ||
offer.avMedia | ||
.filter((av: AvMediaDescription) => av.type === 'video') | ||
.forEach((av: AvMediaDescription) => { | ||
[...av.codecs.values()].forEach((c: CodecInfo) => { | ||
if (c.name?.toLowerCase() !== 'h264') { | ||
throw new Error('SDP contains non-h264 codec in video media description'); | ||
} | ||
}); | ||
}); | ||
offer.avMedia | ||
.filter((av: AvMediaDescription) => av.type === 'audio') | ||
.forEach((av: AvMediaDescription) => { | ||
[...av.codecs.values()].forEach((c: CodecInfo) => { | ||
if (c.name?.toLowerCase() !== 'opus') { | ||
throw new Error('SDP contains non-opus codec in audio media description'); | ||
} | ||
}); | ||
}); | ||
return true; | ||
}; | ||
|
||
describe('munging', () => { | ||
describe('removeCodec', () => { | ||
it('should remove codecs correctly when passing in an SDP', () => { | ||
expect.hasAssertions(); | ||
const offer = fs.readFileSync('./src/sdp-corpus/offer_with_extra_codecs.sdp', 'utf-8'); | ||
const parsed = parse(offer); | ||
|
||
const unwantedVideoCodecs = ['VP8', 'VP9', 'AV1', 'rtx', 'red', 'ulpfec']; | ||
const unwantedAudioCodecs = ['red', 'ISAC', 'G722', 'PCMU', 'PCMA', 'CN', 'telephone-event']; | ||
|
||
unwantedVideoCodecs.forEach((codec) => removeCodec(parsed, codec)); | ||
unwantedAudioCodecs.forEach((codec) => removeCodec(parsed, codec)); | ||
expect(validateOfferCodecs(parsed)).toBe(true); | ||
}); | ||
it('should remove codecs correctly when passing in an AvMediaDescription', () => { | ||
expect.hasAssertions(); | ||
const offer = fs.readFileSync('./src/sdp-corpus/offer_with_extra_codecs.sdp', 'utf-8'); | ||
const parsed = parse(offer); | ||
|
||
const unwantedVideoCodecs = ['VP8', 'VP9', 'AV1', 'rtx', 'red', 'ulpfec']; | ||
const unwantedAudioCodecs = ['red', 'ISAC', 'G722', 'PCMU', 'PCMA', 'CN', 'telephone-event']; | ||
|
||
parsed.avMedia.forEach((av) => { | ||
unwantedVideoCodecs.forEach((codec) => removeCodec(av, codec)); | ||
unwantedAudioCodecs.forEach((codec) => removeCodec(av, codec)); | ||
}); | ||
expect(validateOfferCodecs(parsed)).toBe(true); | ||
}); | ||
}); | ||
describe('retainCodecs', () => { | ||
it('should retain codecs correctly when passing in an SDP', () => { | ||
expect.hasAssertions(); | ||
const offer = fs.readFileSync('./src/sdp-corpus/offer_with_extra_codecs.sdp', 'utf-8'); | ||
const parsed = parse(offer); | ||
|
||
retainCodecs(parsed, ['h264', 'opus']); | ||
expect(validateOfferCodecs(parsed)).toBe(true); | ||
}); | ||
it('should retain codecs correctly when passing in an AvMediaDescription', () => { | ||
expect.hasAssertions(); | ||
const offer = fs.readFileSync('./src/sdp-corpus/offer_with_extra_codecs.sdp', 'utf-8'); | ||
const parsed = parse(offer); | ||
|
||
parsed.avMedia.forEach((av) => { | ||
retainCodecs(av, ['h264', 'opus']); | ||
}); | ||
expect(validateOfferCodecs(parsed)).toBe(true); | ||
}); | ||
}); | ||
|
||
describe('retainCandidates', () => { | ||
it('should retain candidates correctly when passing in an SDP', () => { | ||
expect.hasAssertions(); | ||
const offer = fs.readFileSync('./src/sdp-corpus/answer_with_extra_candidates.sdp', 'utf-8'); | ||
const parsed = parse(offer); | ||
|
||
// should return true when some candidates have been filtered out | ||
expect(retainCandidates(parsed, ['udp', 'tcp'])).toBeTruthy(); | ||
parsed.media.forEach((mline) => { | ||
expect(mline.iceInfo.candidates).toHaveLength(4); | ||
expect( | ||
mline.iceInfo.candidates.every((candidate) => | ||
['udp', 'tcp'].includes(candidate.transport.toLowerCase()) | ||
) | ||
).toBeTruthy(); | ||
}); | ||
// should return false when no candidates have been filtered out | ||
expect(retainCandidates(parsed, ['udp', 'tcp'])).toBeFalsy(); | ||
}); | ||
it('should retain candidates correctly when passing in an AvMediaDescription', () => { | ||
expect.hasAssertions(); | ||
const offer = fs.readFileSync('./src/sdp-corpus/answer_with_extra_candidates.sdp', 'utf-8'); | ||
const parsed = parse(offer); | ||
|
||
parsed.media.forEach((media) => { | ||
// should return true when some candidates have been filtered out | ||
expect(retainCandidates(media, ['udp', 'tcp'])).toBeTruthy(); | ||
expect(media.iceInfo.candidates).toHaveLength(4); | ||
expect( | ||
media.iceInfo.candidates.every((candidate) => | ||
['udp', 'tcp'].includes(candidate.transport.toLowerCase()) | ||
) | ||
).toBeTruthy(); | ||
// should return false when no candidates have been filtered out | ||
expect(retainCandidates(media, ['udp', 'tcp'])).toBeFalsy(); | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
v=0 | ||
o=homer 0 0 IN IP4 10.224.203.38 | ||
s=- | ||
i=linus;homer:focal-3143;mf:3653 | ||
c=IN IP4 10.224.203.38 | ||
b=TIAS:1021256000 | ||
t=0 0 | ||
a=group:BUNDLE 0 1 | ||
a=ice-lite | ||
m=video 5004 RTP/AVP 102 103 | ||
c=IN IP4 10.224.203.38 | ||
b=TIAS:1000000000 | ||
a=content:main | ||
a=sendrecv | ||
a=rtpmap:102 H264/90000 | ||
a=fmtp:102 profile-level-id=420034;packetization-mode=1;max-mbps=2073600;max-fs=36864;max-fps=3000;max-br=1000000;max-dpb=69120;level-asymmetry-allowed=1 | ||
a=rtpmap:103 rtx/90000 | ||
a=fmtp:103 apt=102 | ||
a=rtcp-fb:* goog-remb | ||
a=rtcp-fb:* ccm fir | ||
a=rtcp-fb:* nack | ||
a=rtcp-fb:* nack pli | ||
a=extmap:2/sendrecv http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time | ||
a=rtcp-mux | ||
a=mid:0 | ||
a=jmp:v1 | ||
a=jmp-source:0 | ||
a=jmp-stream-id-mode:SSRC | ||
a=setup:passive | ||
a=fingerprint:sha-256 2B:C0:C2:C8:9D:B0:D3:B1:B6:FC:D2:98:23:40:A4:14:A3:79:99:E1:AA:AD:4C:75:F3:07:F8:13:AB:A5:3F:1F | ||
a=label:0 | ||
a=ice-ufrag:CQkMoaMl | ||
a=ice-pwd:XuRyavxtbUskqv61aunHNusXpaHjll88 | ||
a=candidate:0 1 UDP 2130706431 10.224.203.38 5004 typ host | ||
a=candidate:1 1 UDP 2130706175 10.224.203.38 33434 typ host | ||
a=candidate:2 1 TCP 1962934271 10.224.203.38 5004 typ host tcptype passive | ||
a=candidate:3 1 TCP 1962934015 10.224.203.38 33434 typ host tcptype passive | ||
a=candidate:4 1 xTLS 1795162111 10.224.203.38 443 typ host tcptype passive fingerprint sha-1;C3:C7:01:E9:C0:5D:74:BA:E8:3A:A4:D4:95:F2:75:3A:84:B0:F3:4B | ||
a=rtcp:5005 IN IP4 10.224.203.38 | ||
m=audio 5004 RTP/AVP 111 | ||
c=IN IP4 10.224.203.38 | ||
b=TIAS:1000000 | ||
a=content:main | ||
a=sendrecv | ||
a=rtpmap:111 opus/48000/2 | ||
a=fmtp:111 maxplaybackrate=48000;maxaveragebitrate=64000;stereo=1;sprop-stereo=1;useinbandfec=1 | ||
a=extmap:14/sendrecv urn:ietf:params:rtp-hdrext:ssrc-audio-level | ||
a=extmap:2/sendrecv http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time | ||
a=rtcp-mux | ||
a=mid:1 | ||
a=jmp:v1 | ||
a=jmp-source:0 | ||
a=jmp-stream-id-mode:SSRC | ||
a=setup:passive | ||
a=fingerprint:sha-256 2B:C0:C2:C8:9D:B0:D3:B1:B6:FC:D2:98:23:40:A4:14:A3:79:99:E1:AA:AD:4C:75:F3:07:F8:13:AB:A5:3F:1F | ||
a=label:1 | ||
a=ice-ufrag:TSd3jAfz | ||
a=ice-pwd:IgtEWo1oeuGbnYsnp85PeOETLfXZFrj8 | ||
a=candidate:0 1 UDP 2130706431 10.224.203.38 5004 typ host | ||
a=candidate:1 1 UDP 2130706175 10.224.203.38 33434 typ host | ||
a=candidate:2 1 TCP 1962934271 10.224.203.38 5004 typ host tcptype passive | ||
a=candidate:3 1 TCP 1962934015 10.224.203.38 33434 typ host tcptype passive | ||
a=candidate:4 1 xTLS 1795162111 10.224.203.38 443 typ host tcptype passive fingerprint sha-1;C3:C7:01:E9:C0:5D:74:BA:E8:3A:A4:D4:95:F2:75:3A:84:B0:F3:4B | ||
a=rtcp:5005 IN IP4 10.224.203.38 |
Oops, something went wrong.