1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="pc.js"></script>
</head>
<body>
<pre id="test">
<script type="application/javascript">
createHTML({
bug: "1765005",
title: "Verify audio channel limits for each negotiated audio codec",
});
const matchesChannels = (sdp, codec, channels) =>
!!sdp.match(new RegExp(`a=rtpmap:\\d* ${codec}\/\\d*\/${channels}\r\n`, "g")) ||
(channels <= 1 &&
!!sdp.match(new RegExp(`a=rtpmap:\\d* ${codec}\/\\d*\r\n`, "g")));
async function testAudioChannels(track, codec, channels, accepted, expectedChannels) {
const pc1 = new RTCPeerConnection();
const pc2 = new RTCPeerConnection();
try {
pc1.addTrack(track);
pc1.onicecandidate = e => pc2.addIceCandidate(e.candidate);
pc2.onicecandidate = e => pc1.addIceCandidate(e.candidate);
await pc1.setLocalDescription();
await pc2.setRemoteDescription(pc1.localDescription);
let {type, sdp} = await pc2.createAnswer();
sdp = sdp.replace(new RegExp(`a=rtpmap:(\\d*) ${codec}\/(\\d*)\/?\\d*\r\n`, "g"),
`a=rtpmap:$1 ${codec}/$2/${channels}\r\n`);
const payloadType = Number(sdputils.findCodecId(sdp, codec));
sdp = sdputils.removeAllButPayloadType(sdp, payloadType);
ok(matchesChannels(sdp, codec, channels), "control");
await pc2.setLocalDescription({type, sdp});
is(matchesChannels(pc2.localDescription.sdp, codec, channels),
accepted,
`test pc2.localDescription`);
try {
await pc1.setRemoteDescription(pc2.localDescription);
ok(expectedChannels, "SRD should succeed iff we're expecting channels");
const [receiver] = pc2.getReceivers();
await new Promise(r => receiver.track.onunmute = r);
let stats = await receiver.getStats();
let inboundStat = [...stats.values()].find(({type}) => type == "inbound-rtp");
if (!inboundStat) {
info("work around bug 1765215"); // TODO bug 1765215
await new Promise(r => setTimeout(r, 200));
stats = await receiver.getStats();
inboundStat = [...stats.values()].find(({type}) => type == "inbound-rtp");
}
ok(inboundStat, "has inbound-rtp stats after track unmute (w/workaround)");
const codecStat = stats.get(inboundStat.codecId);
ok(codecStat.mimeType.includes(codec), "correct codec");
is(codecStat.payloadType, payloadType, "correct payloadType");
is(codecStat.channels, expectedChannels, "expected channels");
} catch (e) {
ok(!expectedChannels, "SRD should fail iff we're not expecting channels");
}
} finally {
pc1.close();
pc2.close();
}
}
runNetworkTest(async () => {
const [track] = (await navigator.mediaDevices.getUserMedia({audio: true}))
.getAudioTracks();
try {
for (let [codec, channels, accepted, expectedChannels] of [
["opus", 2, true, 2],
["opus", 1, true, 0],
["opus", 1000, true, 0],
["G722", 1, true, 1],
["G722", 2, true, 0],
["G722", 1000, true, 0],
["PCMU", 1, true, 1],
["PCMU", 2, false, 1],
["PCMU", 1000, false, 1],
["PCMA", 1, true, 1],
["PCMA", 2, false, 1],
["PCMA", 1000, false, 1]
]) {
const testName = `${codec} with ${channels} channel(s) is ` +
`${accepted? "accepted" : "ignored"} and produces ` +
`${expectedChannels || "no"} channels`;
try {
info(`Testing that ${testName}`);
await testAudioChannels(track, codec, channels, accepted, expectedChannels);
} catch (e) {
ok(false, `Error testing that ${testName}: ${e}\n${e.stack}`);
}
}
} finally {
track.stop();
}
});
</script>
</pre>
</body>
</html>
|