зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1719923 [wpt PR 29629] - Add AudioData::copyTo(), a=testonly
Automatic update from web-platform-tests Add AudioData::copyTo() This CL updates AudioData according to the latest WebCodecs spec. It adds an allocationSize() and a copyTo() method to AudioData. WPTs will be included in future CLs, when AudioDataInit is updated to use a BufferSource instead of an AudioBuffer. Bug: 1205281 Change-Id: I97a2ed6ac094e373671262d3ba4089d150d94446 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3011779 Commit-Queue: Thomas Guilbert <tguilbert@chromium.org> Reviewed-by: Dan Sanders <sandersd@chromium.org> Reviewed-by: Jeremy Roman <jbroman@chromium.org> Cr-Commit-Position: refs/heads/master@{#900655} -- wpt-commits: 3ecb64d20dd5ddfaa067183d58dafc75a7fc6614 wpt-pr: 29629
This commit is contained in:
Родитель
c9e29f0c91
Коммит
5f38c4012c
|
@ -17,55 +17,59 @@ function createDefaultAudioData() {
|
|||
}
|
||||
|
||||
async_test(t => {
|
||||
let localData = createDefaultAudioData();
|
||||
let originalData = createDefaultAudioData();
|
||||
|
||||
let channel = new MessageChannel();
|
||||
let localPort = channel.port1;
|
||||
let externalPort = channel.port2;
|
||||
|
||||
externalPort.onmessage = t.step_func((e) => {
|
||||
let externalData = e.data;
|
||||
let buffer = externalData.buffer;
|
||||
// We should have a valid deserialized buffer.
|
||||
assert_true(buffer != undefined || buffer != null);
|
||||
assert_equals(buffer.numberOfChannels,
|
||||
localData.buffer.numberOfChannels, "numberOfChannels");
|
||||
let newData = e.data;
|
||||
|
||||
for (var channel = 0; channel < buffer.numberOfChannels; channel++) {
|
||||
// This gives us the actual array that contains the data
|
||||
var dest_array = buffer.getChannelData(channel);
|
||||
var source_array = localData.buffer.getChannelData(channel);
|
||||
for (var i = 0; i < dest_array.length; i+=10) {
|
||||
assert_equals(dest_array[i], source_array[i],
|
||||
// We should have a valid deserialized buffer.
|
||||
assert_equals(newData.numberOfFrames, defaultInit.frames, 'numberOfFrames');
|
||||
assert_equals(
|
||||
newData.numberOfChannels, defaultInit.channels, 'numberOfChannels');
|
||||
assert_equals(newData.sampleRate, defaultInit.sampleRate, 'sampleRate');
|
||||
|
||||
const originalData_copyDest = new Float32Array(defaultInit.frames);
|
||||
const newData_copyDest = new Float32Array(defaultInit.frames);
|
||||
|
||||
for (var channel = 0; channel < defaultInit.channels; channel++) {
|
||||
originalData.copyTo(originalData_copyDest, { planeIndex: channel});
|
||||
newData.copyTo(newData_copyDest, { planeIndex: channel});
|
||||
|
||||
for (var i = 0; i < newData_copyDest.length; i+=10) {
|
||||
assert_equals(newData_copyDest[i], originalData_copyDest[i],
|
||||
"data (ch=" + channel + ", i=" + i + ")");
|
||||
}
|
||||
}
|
||||
|
||||
externalData.close();
|
||||
newData.close();
|
||||
externalPort.postMessage("Done");
|
||||
})
|
||||
|
||||
localPort.onmessage = t.step_func_done((e) => {
|
||||
assert_true(localData.buffer != null);
|
||||
localData.close();
|
||||
assert_equals(originalData.numberOfFrames, defaultInit.frames);
|
||||
originalData.close();
|
||||
})
|
||||
|
||||
localPort.postMessage(localData);
|
||||
localPort.postMessage(originalData);
|
||||
|
||||
}, 'Verify closing AudioData does not propagate accross contexts.');
|
||||
|
||||
async_test(t => {
|
||||
let localData = createDefaultAudioData();
|
||||
let data = createDefaultAudioData();
|
||||
|
||||
let channel = new MessageChannel();
|
||||
let localPort = channel.port1;
|
||||
|
||||
localPort.onmessage = t.unreached_func();
|
||||
|
||||
localData.close();
|
||||
data.close();
|
||||
|
||||
assert_throws_dom("DataCloneError", () => {
|
||||
localPort.postMessage(localData);
|
||||
localPort.postMessage(data);
|
||||
});
|
||||
|
||||
t.done();
|
||||
|
|
|
@ -29,10 +29,10 @@ test(t => {
|
|||
let data = new AudioData(audioDataInit);
|
||||
|
||||
assert_equals(data.timestamp, defaultInit.timestamp, 'timestamp');
|
||||
assert_equals(data.buffer.length, defaultInit.frames, 'frames');
|
||||
assert_equals(
|
||||
data.buffer.numberOfChannels, defaultInit.channels, 'channels');
|
||||
assert_equals(data.buffer.sampleRate, defaultInit.sampleRate, 'sampleRate');
|
||||
assert_equals(data.numberOfFrames, defaultInit.frames, 'frames');
|
||||
assert_equals(data.numberOfChannels, defaultInit.channels, 'channels');
|
||||
assert_equals(data.sampleRate, defaultInit.sampleRate, 'sampleRate');
|
||||
assert_equals(data.format, "FLTP", 'format');
|
||||
|
||||
assert_throws_js(
|
||||
TypeError, () => {let data = new AudioData({buffer: localBuffer})},
|
||||
|
@ -51,60 +51,36 @@ test(t => {
|
|||
|
||||
// Verify the parameters match.
|
||||
assert_equals(data.timestamp, clone.timestamp, 'timestamp');
|
||||
assert_equals(data.buffer.length, clone.buffer.length, 'frames');
|
||||
assert_equals(data.numberOfFrames, clone.numberOfFrames, 'frames');
|
||||
assert_equals(
|
||||
data.buffer.numberOfChannels, clone.buffer.numberOfChannels, 'channels');
|
||||
assert_equals(data.buffer.sampleRate, clone.buffer.sampleRate, 'sampleRate');
|
||||
data.numberOfChannels, clone.numberOfChannels, 'channels');
|
||||
assert_equals(data.sampleRate, clone.sampleRate, 'sampleRate');
|
||||
assert_equals(data.format, clone.format, 'format');
|
||||
|
||||
const data_copyDest = new Float32Array(defaultInit.frames);
|
||||
const clone_copyDest = new Float32Array(defaultInit.frames);
|
||||
|
||||
// Verify the data matches.
|
||||
for (var channel = 0; channel < data.buffer.numberOfChannels; channel++) {
|
||||
var orig_ch = data.buffer.getChannelData(channel);
|
||||
var cloned_ch = clone.buffer.getChannelData(channel);
|
||||
for (var channel = 0; channel < defaultInit.channels; channel++) {
|
||||
data.copyTo(data_copyDest, {planeIndex: channel});
|
||||
clone.copyTo(clone_copyDest, {planeIndex: channel});
|
||||
|
||||
assert_array_equals(orig_ch, cloned_ch, 'Cloned data ch=' + channel);
|
||||
assert_array_equals(
|
||||
data_copyDest, clone_copyDest, 'Cloned data ch=' + channel);
|
||||
}
|
||||
|
||||
// Verify closing the original data doesn't close the clone.
|
||||
data.close();
|
||||
assert_equals(data.buffer, null, 'data.buffer (closed)');
|
||||
assert_not_equals(clone.buffer, null, 'clone.buffer (not closed)');
|
||||
assert_equals(data.numberOfFrames, 0, 'data.buffer (closed)');
|
||||
assert_not_equals(clone.numberOfFrames, 0, 'clone.buffer (not closed)');
|
||||
|
||||
clone.close();
|
||||
assert_equals(clone.buffer, null, 'clone.buffer (closed)');
|
||||
assert_equals(clone.numberOfFrames, 0, 'clone.buffer (closed)');
|
||||
|
||||
// Verify closing a closed AudioData does not throw.
|
||||
data.close();
|
||||
}, 'Verify closing and cloning AudioData');
|
||||
|
||||
test(t => {
|
||||
let data = createDefaultAudioData();
|
||||
|
||||
// Get a copy of the original data.
|
||||
let pre_modification_clone = data.clone();
|
||||
|
||||
for (var channel = 0; channel < data.buffer.numberOfChannels; channel++) {
|
||||
var orig_ch = data.buffer.getChannelData(channel);
|
||||
|
||||
// Flip the polarity of the original data's buffer.
|
||||
for (let i = 0; i < orig_ch.length; ++i) {
|
||||
orig_ch.buffer[i] = -orig_ch.buffer[i];
|
||||
}
|
||||
}
|
||||
|
||||
// The data in 'data' should have been snapshotted internally, and
|
||||
// despite changes to data.buffer, post_modification_clone should not contain
|
||||
// modified data.
|
||||
let post_modification_clone = data.clone();
|
||||
|
||||
// Verify the data matches.
|
||||
for (var channel = 0; channel < data.buffer.numberOfChannels; channel++) {
|
||||
var pre_ch = pre_modification_clone.buffer.getChannelData(channel);
|
||||
var post_ch = post_modification_clone.buffer.getChannelData(channel);
|
||||
|
||||
assert_array_equals(pre_ch, post_ch, 'Cloned data ch=' + channel);
|
||||
}
|
||||
}, 'Verify AudioData is snapshotted and internally immutable');
|
||||
|
||||
test(t => {
|
||||
let data = make_audio_data(
|
||||
-10, defaultInit.channels, defaultInit.sampleRate, defaultInit.frames);
|
||||
|
|
|
@ -2,32 +2,69 @@
|
|||
// META: script=/webcodecs/utils.js
|
||||
|
||||
// Merge all audio buffers into a new big one with all the data.
|
||||
function join_buffers(buffers) {
|
||||
assert_greater_than_equal(buffers.length, 0);
|
||||
let total_length = 0;
|
||||
let base_buffer = buffers[0];
|
||||
for (const buffer of buffers) {
|
||||
assert_not_equals(buffer, null);
|
||||
assert_equals(buffer.sampleRate, base_buffer.sampleRate);
|
||||
assert_equals(buffer.numberOfChannels, base_buffer.numberOfChannels);
|
||||
total_length += buffer.length;
|
||||
function join_audio_data(audio_data_array) {
|
||||
assert_greater_than_equal(audio_data_array.length, 0);
|
||||
let total_frames = 0;
|
||||
let base_buffer = audio_data_array[0];
|
||||
for (const data of audio_data_array) {
|
||||
assert_not_equals(data, null);
|
||||
assert_equals(data.sampleRate, base_buffer.sampleRate);
|
||||
assert_equals(data.numberOfChannels, base_buffer.numberOfChannels);
|
||||
assert_equals(data.format, base_buffer.format);
|
||||
total_frames += data.numberOfFrames;
|
||||
}
|
||||
|
||||
let result = new AudioBuffer({
|
||||
length: total_length,
|
||||
numberOfChannels: base_buffer.numberOfChannels,
|
||||
sampleRate: base_buffer.sampleRate
|
||||
});
|
||||
assert_true(base_buffer.format == 'FLT' || base_buffer.format == 'FLTP');
|
||||
|
||||
for (let i = 0; i < base_buffer.numberOfChannels; i++) {
|
||||
let channel = result.getChannelData(i);
|
||||
if (base_buffer.format == 'FLT')
|
||||
return join_interleaved_data(audio_data_array, total_frames);
|
||||
|
||||
// The format is 'FLTP'.
|
||||
return join_planar_data(audio_data_array, total_frames);
|
||||
}
|
||||
|
||||
function join_interleaved_data(audio_data_array, total_frames) {
|
||||
let base_data = audio_data_array[0];
|
||||
let channels = base_data.numberOfChannels;
|
||||
let total_samples = total_frames * channels;
|
||||
|
||||
let result = new Float32Array(total_samples);
|
||||
|
||||
let copy_dest = new Float32Array(base_data.numberOfFrames * channels);
|
||||
|
||||
// Copy all the interleaved data.
|
||||
let position = 0;
|
||||
for (const buffer of buffers) {
|
||||
channel.set(buffer.getChannelData(i), position);
|
||||
position += buffer.length;
|
||||
for (const data of audio_data_array) {
|
||||
let samples = data.numberOfFrames * channels;
|
||||
if (copy_dest.length < samples)
|
||||
copy_dest = new Float32Array(samples);
|
||||
|
||||
data.copyTo(copy_dest, {planeIndex: 0});
|
||||
result.set(copy_dest, position);
|
||||
position += samples;
|
||||
}
|
||||
assert_equals(position, total_length);
|
||||
|
||||
assert_equals(position, total_samples);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function join_planar_data(audio_data_array, total_frames) {
|
||||
let base_frames = audio_data_array[0].numberOfFrames;
|
||||
let channels = audio_data_array[0].numberOfChannels;
|
||||
let result = new Float32Array(total_frames*channels);
|
||||
let copyDest = new Float32Array(base_frames);
|
||||
|
||||
// Merge all samples and lay them out according to the FLTP memory layout.
|
||||
let position = 0;
|
||||
for (let ch = 0; ch < channels; ch++) {
|
||||
for (const data of audio_data_array) {
|
||||
data.copyTo(copyDest, { planeIndex: ch});
|
||||
result.set(copyDest, position);
|
||||
position += data.numberOfFrames;
|
||||
}
|
||||
}
|
||||
assert_equals(position, total_frames * channels);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -167,9 +204,9 @@ function channelNumberVariationTests() {
|
|||
let length = sample_rate / 10;
|
||||
let data1 = make_audio_data(ts, channels, sample_rate, length);
|
||||
|
||||
ts += Math.floor(data1.buffer.duration / 1000000);
|
||||
ts += Math.floor(data1.duration / 1000000);
|
||||
let data2 = make_audio_data(ts, channels, sample_rate, length);
|
||||
ts += Math.floor(data2.buffer.duration / 1000000);
|
||||
ts += Math.floor(data2.duration / 1000000);
|
||||
|
||||
let bad_data = make_audio_data(ts, channels + 1, sample_rate, length);
|
||||
promise_test(async t =>
|
||||
|
@ -193,9 +230,9 @@ function sampleRateVariationTests() {
|
|||
let length = sample_rate / 10;
|
||||
let data1 = make_audio_data(ts, channels, sample_rate, length);
|
||||
|
||||
ts += Math.floor(data1.buffer.duration / 1000000);
|
||||
ts += Math.floor(data1.duration / 1000000);
|
||||
let data2 = make_audio_data(ts, channels, sample_rate, length);
|
||||
ts += Math.floor(data2.buffer.duration / 1000000);
|
||||
ts += Math.floor(data2.duration / 1000000);
|
||||
|
||||
let bad_data = make_audio_data(ts, channels, sample_rate + 333, length);
|
||||
promise_test(async t =>
|
||||
|
@ -255,28 +292,45 @@ promise_test(async t => {
|
|||
decoder.close();
|
||||
|
||||
|
||||
let total_input = join_buffers(input_data.map(f => f.buffer));
|
||||
let total_output = join_buffers(output_data.map(f => f.buffer));
|
||||
assert_equals(total_output.numberOfChannels, 2);
|
||||
assert_equals(total_output.sampleRate, sample_rate);
|
||||
let total_input = join_audio_data(input_data);
|
||||
let frames_per_plane = total_input.length / config.numberOfChannels;
|
||||
|
||||
let total_output = join_audio_data(output_data);
|
||||
|
||||
let base_input = input_data[0];
|
||||
let base_output = output_data[0];
|
||||
|
||||
// TODO: Convert formats to simplify conversions, once
|
||||
// https://github.com/w3c/webcodecs/issues/232 is resolved.
|
||||
assert_equals(base_input.format, "FLTP");
|
||||
assert_equals(base_output.format, "FLT");
|
||||
|
||||
assert_equals(base_output.numberOfChannels, config.numberOfChannels);
|
||||
assert_equals(base_output.sampleRate, sample_rate);
|
||||
|
||||
// Output can be slightly longer that the input due to padding
|
||||
assert_greater_than_equal(total_output.length, total_input.length);
|
||||
assert_greater_than_equal(total_output.duration, total_duration_s);
|
||||
assert_approx_equals(total_output.duration, total_duration_s, 0.1);
|
||||
|
||||
// Compare waveform before and after encoding
|
||||
for (let channel = 0; channel < total_input.numberOfChannels; channel++) {
|
||||
let input_data = total_input.getChannelData(channel);
|
||||
let output_data = total_output.getChannelData(channel);
|
||||
for (let i = 0; i < total_input.length; i += 10) {
|
||||
for (let channel = 0; channel < base_input.numberOfChannels; channel++) {
|
||||
|
||||
let plane_start = channel * frames_per_plane;
|
||||
let input_plane = total_input.slice(
|
||||
plane_start, plane_start + frames_per_plane);
|
||||
|
||||
for (let i = 0; i < base_input.numberOfFrames; i += 10) {
|
||||
// Instead of de-interleaving the data, directly look into |total_output|
|
||||
// for the sample we are interested in.
|
||||
let ouput_index = i * base_input.numberOfChannels + channel;
|
||||
|
||||
// Checking only every 10th sample to save test time in slow
|
||||
// configurations like MSAN etc.
|
||||
assert_approx_equals(input_data[i], output_data[i], 0.5,
|
||||
"Difference between input and output is too large."
|
||||
+ " index: " + i
|
||||
+ " input: " + input_data[i]
|
||||
+ " output: " + output_data[i]);
|
||||
assert_approx_equals(
|
||||
input_plane[i], total_output[ouput_index], 0.5,
|
||||
'Difference between input and output is too large.' +
|
||||
' index: ' + i + ' channel: ' + channel +
|
||||
' input: ' + input_plane[i] +
|
||||
' output: ' + total_output[ouput_index]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче