Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- This WPT test may be referenced by the following Test IDs:
- /webcodecs/audio-data-copyto-offset.any.html - WPT Dashboard Interop Dashboard
- /webcodecs/audio-data-copyto-offset.any.worker.html - WPT Dashboard Interop Dashboard
// META: global=window,dedicatedworker
test(t => {
// 2 channels, 10 frames, interleaved f32.
// Layout: [L0, R0, L1, R1, L2, R2, L3, R3, L4, R4,
// L5, R5, L6, R6, L7, R7, L8, R8, L9, R9]
const channels = 2;
const frames = 10;
const data = new Float32Array(channels * frames);
for (let i = 0; i < frames; i++) {
data[i * channels] = i * 0.1; // left
data[i * channels + 1] = -(i * 0.1); // right
}
const audioData = new AudioData({
timestamp: 0,
data: data,
numberOfFrames: frames,
numberOfChannels: channels,
sampleRate: 44100,
format: 'f32',
});
t.add_cleanup(() => audioData.close());
const frameOffset = 3;
const frameCount = 5;
const dest = new Float32Array(channels * frameCount);
audioData.copyTo(dest, {
planeIndex: 0,
format: 'f32',
frameOffset: frameOffset,
frameCount: frameCount,
});
// Expected: frames 3 through 7, interleaved.
for (let i = 0; i < frameCount; i++) {
const srcFrame = frameOffset + i;
const expectedL = srcFrame * 0.1;
const expectedR = -(srcFrame * 0.1);
assert_approx_equals(dest[i * channels], expectedL, 1e-6,
`frame ${srcFrame} left channel`);
assert_approx_equals(dest[i * channels + 1], expectedR, 1e-6,
`frame ${srcFrame} right channel`);
}
}, 'copyTo interleaved-to-interleaved with non-zero frameOffset');
test(t => {
// Same test with s16 to ensure it's not float-specific.
const channels = 2;
const frames = 10;
const data = new Int16Array(channels * frames);
for (let i = 0; i < frames; i++) {
data[i * channels] = i * 1000;
data[i * channels + 1] = -(i * 1000);
}
const audioData = new AudioData({
timestamp: 0,
data: data,
numberOfFrames: frames,
numberOfChannels: channels,
sampleRate: 44100,
format: 's16',
});
t.add_cleanup(() => audioData.close());
const frameOffset = 4;
const frameCount = 3;
const dest = new Int16Array(channels * frameCount);
audioData.copyTo(dest, {
planeIndex: 0,
format: 's16',
frameOffset: frameOffset,
frameCount: frameCount,
});
for (let i = 0; i < frameCount; i++) {
const srcFrame = frameOffset + i;
assert_equals(dest[i * channels], srcFrame * 1000,
`frame ${srcFrame} left channel`);
assert_equals(dest[i * channels + 1], -(srcFrame * 1000),
`frame ${srcFrame} right channel`);
}
}, 'copyTo interleaved-to-interleaved s16 with non-zero frameOffset');
test(t => {
// 3 channels, interleaved, to cover more than the stereo case.
const channels = 3;
const frames = 8;
const data = new Float32Array(channels * frames);
for (let i = 0; i < frames; i++) {
for (let ch = 0; ch < channels; ch++) {
data[i * channels + ch] = i + ch * 0.01;
}
}
const audioData = new AudioData({
timestamp: 0,
data: data,
numberOfFrames: frames,
numberOfChannels: channels,
sampleRate: 44100,
format: 'f32',
});
t.add_cleanup(() => audioData.close());
const frameOffset = 2;
const frameCount = 4;
const dest = new Float32Array(channels * frameCount);
audioData.copyTo(dest, {
planeIndex: 0,
format: 'f32',
frameOffset: frameOffset,
frameCount: frameCount,
});
for (let i = 0; i < frameCount; i++) {
const srcFrame = frameOffset + i;
for (let ch = 0; ch < channels; ch++) {
const expected = srcFrame + ch * 0.01;
assert_approx_equals(
dest[i * channels + ch], expected, 1e-6,
`frame ${srcFrame} channel ${ch}`);
}
}
}, 'copyTo interleaved-to-interleaved f32 with 3 channels and frameOffset');
test(t => {
// 2 channels, 10 frames, planar f32.
// Layout: [L0, L1, ..., L9, R0, R1, ..., R9]
const channels = 2;
const frames = 10;
const data = new Float32Array(channels * frames);
for (let ch = 0; ch < channels; ch++) {
for (let i = 0; i < frames; i++) {
data[ch * frames + i] = (ch + 1) * (i + 1) * 0.1;
}
}
const audioData = new AudioData({
timestamp: 0,
data: data,
numberOfFrames: frames,
numberOfChannels: channels,
sampleRate: 44100,
format: 'f32-planar',
});
t.add_cleanup(() => audioData.close());
const frameOffset = 3;
const frameCount = 5;
const dest = new Float32Array(channels * frameCount);
audioData.copyTo(dest, {
planeIndex: 0,
format: 'f32',
frameOffset: frameOffset,
frameCount: frameCount,
});
// Expected: frames 3 through 7 from each channel, interleaved.
for (let i = 0; i < frameCount; i++) {
const srcFrame = frameOffset + i;
for (let ch = 0; ch < channels; ch++) {
const expected = (ch + 1) * (srcFrame + 1) * 0.1;
assert_approx_equals(
dest[i * channels + ch], expected, 1e-5,
`frame ${srcFrame} channel ${ch}`);
}
}
}, 'copyTo planar-to-interleaved with non-zero frameOffset');
test(t => {
// 3 channels, planar s16.
const channels = 3;
const frames = 8;
const data = new Int16Array(channels * frames);
for (let ch = 0; ch < channels; ch++) {
for (let i = 0; i < frames; i++) {
data[ch * frames + i] = (ch + 1) * 1000 + i;
}
}
const audioData = new AudioData({
timestamp: 0,
data: data,
numberOfFrames: frames,
numberOfChannels: channels,
sampleRate: 44100,
format: 's16-planar',
});
t.add_cleanup(() => audioData.close());
const frameOffset = 2;
const frameCount = 4;
const dest = new Int16Array(channels * frameCount);
audioData.copyTo(dest, {
planeIndex: 0,
format: 's16',
frameOffset: frameOffset,
frameCount: frameCount,
});
for (let i = 0; i < frameCount; i++) {
const srcFrame = frameOffset + i;
for (let ch = 0; ch < channels; ch++) {
const expected = (ch + 1) * 1000 + srcFrame;
assert_equals(
dest[i * channels + ch], expected,
`frame ${srcFrame} channel ${ch}`);
}
}
}, 'copyTo planar-to-interleaved s16 with 3 channels and frameOffset');
test(t => {
// Verify frameOffset=0 still works correctly for planar-to-interleaved
// (baseline sanity check).
const channels = 2;
const frames = 4;
const data = new Float32Array([
1.0, 2.0, 3.0, 4.0, // channel 0
5.0, 6.0, 7.0, 8.0, // channel 1
]);
const audioData = new AudioData({
timestamp: 0,
data: data,
numberOfFrames: frames,
numberOfChannels: channels,
sampleRate: 44100,
format: 'f32-planar',
});
t.add_cleanup(() => audioData.close());
const dest = new Float32Array(channels * frames);
audioData.copyTo(dest, {planeIndex: 0, format: 'f32'});
// Expected interleaved: [1, 5, 2, 6, 3, 7, 4, 8]
const expected = new Float32Array([1, 5, 2, 6, 3, 7, 4, 8]);
assert_array_equals(dest, expected,
'planar-to-interleaved with frameOffset=0');
}, 'copyTo planar-to-interleaved baseline with frameOffset=0');