Files
sousa-gecko/testing/web-platform/tests/webrtc/RTCRtpEncodingParameters-codec-opus-stereo.https.html
T
Henrik Boström 1bc525f876 Bug 1933658 [wpt PR 49392] - Update stereo opus test to expect upmixing., a=testonly
Automatic update from web-platform-tests
Update stereo opus test to expect upmixing.

Update the test that sends and receives a local mono track with opus
that on the remote side the channelCount is 2 because the opus decoder
performs upmixing.

This strange behavior is option 1) discussed in
https://github.com/w3c/webrtc-pc/issues/3010. This allows for some
optimization and simplifications which aids in virtual audio SSRC use
case of flip-flopping between mono and stereo signals on the wire and
not having to re-initialize the decoder (which could cause glitches).

The vibe from the November Virtual Interim
(https://www.w3.org/2024/11/19-webrtc-minutes.html#561c) was to
standardize what libwebrtc does when stereo is enabled, and this is
what it does.

Note: We still fail the test today though because "stereo opus" has not
been enabled-by-default. When it is the expectation is that we pass
both of these tests.

Bug: webrtc:379996136
Change-Id: Ibd6ee91a59d7c673bf53ad2302ba33f16b8b4ede
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6049355
Reviewed-by: Harald Alvestrand <hta@chromium.org>
Commit-Queue: Henrik Boström <hbos@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1388674}

--

wpt-commits: d97f56c5831beb33c9302d2dd2707554bd842116
wpt-pr: 49392
2024-11-28 11:58:03 +00:00

116 lines
4.4 KiB
HTML

<!DOCTYPE html>
<meta charset="utf-8">
<title>RTCRtpEncodingParameters codec opus stereo</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
'use strict';
const kNumChannelsMono = 1;
const kNumChannelsStereo = 2;
const kAudioProcessingEnabled = true;
const kAudioProcessingDisabled = false;
// In some implementations (e.g. Chrome), whether or not audio processing is
// used may affect the number of channels we get.
// To isolate this factor from the test, we constrain both channels and APM.
function getAudioConstraints(numChannels, audioProcessing) {
return {
channelCount: {exact: numChannels},
autoGainControl: audioProcessing,
echoCancellation: audioProcessing,
noiseSuppression: audioProcessing
};
}
// Polls getSettings() until `channelCount` is known.
// Remote tracks don't populate their `channelCount` until media is received.
async function pollChannelCount(t, track) {
while (true) {
if (track.getSettings().channelCount != undefined) {
break;
}
await new Promise(r => t.step_timeout(r, 50));
}
return track.getSettings().channelCount;
}
promise_test(async t => {
const pc1 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
const pc2 = new RTCPeerConnection();
t.add_cleanup(() => pc2.close());
pc1.onicecandidate = e => pc2.addIceCandidate(e.candidate);
pc2.onicecandidate = e => pc1.addIceCandidate(e.candidate);
// Open microphone as mono.
const stream = await navigator.mediaDevices.getUserMedia(
{audio: getAudioConstraints(kNumChannelsMono, kAudioProcessingEnabled)});
const [track] = stream.getTracks();
t.add_cleanup(() => track.stop());
// Prerequisite of the test.
assert_equals(track.getSettings().channelCount, 1,
'Can open track in mono');
// Negotiate opus.
const transceiver = pc1.addTransceiver(track);
transceiver.setCodecPreferences(
RTCRtpSender.getCapabilities('audio').codecs.filter(
codec => codec.mimeType == 'audio/opus'));
await pc1.setLocalDescription();
await pc2.setRemoteDescription(pc1.localDescription);
await pc2.setLocalDescription();
await pc1.setRemoteDescription(pc2.localDescription);
const [receiver] = pc2.getReceivers();
const remoteTrack = receiver.track;
// Attaching the track to an audio element is needed for media to flow,
// otherwise the `channelCount` is never known.
const audio = document.createElement('audio');
audio.srcObject = new MediaStream();
audio.srcObject.addTrack(remoteTrack);
// The stereo opus decoder outputs stereo regardless of the signal on the
// wire.
assert_equals(await pollChannelCount(t, remoteTrack), 2,
'Remote track is stereo (despite local track being mono)');
}, 'Sending and receiving a mono track with opus (stereo decoder upmix)');
promise_test(async t => {
const pc1 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
const pc2 = new RTCPeerConnection();
t.add_cleanup(() => pc2.close());
pc1.onicecandidate = e => pc2.addIceCandidate(e.candidate);
pc2.onicecandidate = e => pc1.addIceCandidate(e.candidate);
// Open microphone as stereo.
const stream = await navigator.mediaDevices.getUserMedia(
{audio: getAudioConstraints(kNumChannelsStereo, kAudioProcessingDisabled)});
const [track] = stream.getTracks();
t.add_cleanup(() => track.stop());
// Prerequisite of the test.
assert_equals(track.getSettings().channelCount, 2,
'Can open track in stereo');
// Negotiate opus.
const transceiver = pc1.addTransceiver(track);
transceiver.setCodecPreferences(
RTCRtpSender.getCapabilities('audio').codecs.filter(
codec => codec.mimeType == 'audio/opus'));
await pc1.setLocalDescription();
await pc2.setRemoteDescription(pc1.localDescription);
await pc2.setLocalDescription();
await pc1.setRemoteDescription(pc2.localDescription);
const [receiver] = pc2.getReceivers();
const remoteTrack = receiver.track;
// Attaching the track to an audio element is needed for media to flow,
// otherwise the `channelCount` is never known.
const audio = document.createElement('audio');
audio.srcObject = new MediaStream();
audio.srcObject.addTrack(remoteTrack);
assert_equals(await pollChannelCount(t, remoteTrack), 2,
'Remote track is also stereo');
}, 'Sending and receiving a stereo track with opus');
</script>