mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-22 00:17:32 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
367
dom/media/webaudio/test/test_mediaDecoding.html
Normal file
367
dom/media/webaudio/test/test_mediaDecoding.html
Normal file
|
|
@ -0,0 +1,367 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test the decodeAudioData API and Resampling</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script src="webaudio.js" type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
// These routines have been copied verbatim from WebKit, and are used in order
|
||||
// to convert a memory buffer into a wave buffer.
|
||||
function writeString(s, a, offset) {
|
||||
for (var i = 0; i < s.length; ++i) {
|
||||
a[offset + i] = s.charCodeAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
function writeInt16(n, a, offset) {
|
||||
n = Math.floor(n);
|
||||
|
||||
var b1 = n & 255;
|
||||
var b2 = (n >> 8) & 255;
|
||||
|
||||
a[offset + 0] = b1;
|
||||
a[offset + 1] = b2;
|
||||
}
|
||||
|
||||
function writeInt32(n, a, offset) {
|
||||
n = Math.floor(n);
|
||||
var b1 = n & 255;
|
||||
var b2 = (n >> 8) & 255;
|
||||
var b3 = (n >> 16) & 255;
|
||||
var b4 = (n >> 24) & 255;
|
||||
|
||||
a[offset + 0] = b1;
|
||||
a[offset + 1] = b2;
|
||||
a[offset + 2] = b3;
|
||||
a[offset + 3] = b4;
|
||||
}
|
||||
|
||||
function writeAudioBuffer(audioBuffer, a, offset) {
|
||||
var n = audioBuffer.length;
|
||||
var channels = audioBuffer.numberOfChannels;
|
||||
|
||||
for (var i = 0; i < n; ++i) {
|
||||
for (var k = 0; k < channels; ++k) {
|
||||
var buffer = audioBuffer.getChannelData(k);
|
||||
var sample = buffer[i] * 32768.0;
|
||||
|
||||
// Clip samples to the limitations of 16-bit.
|
||||
// If we don't do this then we'll get nasty wrap-around distortion.
|
||||
if (sample < -32768)
|
||||
sample = -32768;
|
||||
if (sample > 32767)
|
||||
sample = 32767;
|
||||
|
||||
writeInt16(sample, a, offset);
|
||||
offset += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createWaveFileData(audioBuffer) {
|
||||
var frameLength = audioBuffer.length;
|
||||
var numberOfChannels = audioBuffer.numberOfChannels;
|
||||
var sampleRate = audioBuffer.sampleRate;
|
||||
var bitsPerSample = 16;
|
||||
var byteRate = sampleRate * numberOfChannels * bitsPerSample/8;
|
||||
var blockAlign = numberOfChannels * bitsPerSample/8;
|
||||
var wavDataByteLength = frameLength * numberOfChannels * 2; // 16-bit audio
|
||||
var headerByteLength = 44;
|
||||
var totalLength = headerByteLength + wavDataByteLength;
|
||||
|
||||
var waveFileData = new Uint8Array(totalLength);
|
||||
|
||||
var subChunk1Size = 16; // for linear PCM
|
||||
var subChunk2Size = wavDataByteLength;
|
||||
var chunkSize = 4 + (8 + subChunk1Size) + (8 + subChunk2Size);
|
||||
|
||||
writeString("RIFF", waveFileData, 0);
|
||||
writeInt32(chunkSize, waveFileData, 4);
|
||||
writeString("WAVE", waveFileData, 8);
|
||||
writeString("fmt ", waveFileData, 12);
|
||||
|
||||
writeInt32(subChunk1Size, waveFileData, 16); // SubChunk1Size (4)
|
||||
writeInt16(1, waveFileData, 20); // AudioFormat (2)
|
||||
writeInt16(numberOfChannels, waveFileData, 22); // NumChannels (2)
|
||||
writeInt32(sampleRate, waveFileData, 24); // SampleRate (4)
|
||||
writeInt32(byteRate, waveFileData, 28); // ByteRate (4)
|
||||
writeInt16(blockAlign, waveFileData, 32); // BlockAlign (2)
|
||||
writeInt32(bitsPerSample, waveFileData, 34); // BitsPerSample (4)
|
||||
|
||||
writeString("data", waveFileData, 36);
|
||||
writeInt32(subChunk2Size, waveFileData, 40); // SubChunk2Size (4)
|
||||
|
||||
// Write actual audio data starting at offset 44.
|
||||
writeAudioBuffer(audioBuffer, waveFileData, 44);
|
||||
|
||||
return waveFileData;
|
||||
}
|
||||
|
||||
</script>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// fuzzTolerance and fuzzToleranceMobile are used to determine fuzziness
|
||||
// thresholds. They're needed to make sure that we can deal with neglibible
|
||||
// differences in the binary buffer caused as a result of resampling the
|
||||
// audio. fuzzToleranceMobile is typically larger on mobile platforms since
|
||||
// we do fixed-point resampling as opposed to floating-point resampling on
|
||||
// those platforms.
|
||||
var files = [
|
||||
// An ogg file, 44.1khz, mono
|
||||
{
|
||||
url: "ting-44.1k-1ch.ogg",
|
||||
valid: true,
|
||||
expectedUrl: "ting-44.1k-1ch.wav",
|
||||
numberOfChannels: 1,
|
||||
frames: 30592,
|
||||
sampleRate: 44100,
|
||||
duration: 0.693,
|
||||
fuzzTolerance: 5,
|
||||
fuzzToleranceMobile: 1284
|
||||
},
|
||||
// An ogg file, 44.1khz, stereo
|
||||
{
|
||||
url: "ting-44.1k-2ch.ogg",
|
||||
valid: true,
|
||||
expectedUrl: "ting-44.1k-2ch.wav",
|
||||
numberOfChannels: 2,
|
||||
frames: 30592,
|
||||
sampleRate: 44100,
|
||||
duration: 0.693,
|
||||
fuzzTolerance: 6,
|
||||
fuzzToleranceMobile: 2544
|
||||
},
|
||||
// An ogg file, 48khz, mono
|
||||
{
|
||||
url: "ting-48k-1ch.ogg",
|
||||
valid: true,
|
||||
expectedUrl: "ting-48k-1ch.wav",
|
||||
numberOfChannels: 1,
|
||||
frames: 33297,
|
||||
sampleRate: 48000,
|
||||
duration: 0.693,
|
||||
fuzzTolerance: 5,
|
||||
fuzzToleranceMobile: 1388
|
||||
},
|
||||
// An ogg file, 48khz, stereo
|
||||
{
|
||||
url: "ting-48k-2ch.ogg",
|
||||
valid: true,
|
||||
expectedUrl: "ting-48k-2ch.wav",
|
||||
numberOfChannels: 2,
|
||||
frames: 33297,
|
||||
sampleRate: 48000,
|
||||
duration: 0.693,
|
||||
fuzzTolerance: 14,
|
||||
fuzzToleranceMobile: 2752
|
||||
},
|
||||
// Make sure decoding a wave file results in the same buffer (for both the
|
||||
// resampling and non-resampling cases)
|
||||
{
|
||||
url: "ting-44.1k-1ch.wav",
|
||||
valid: true,
|
||||
expectedUrl: "ting-44.1k-1ch.wav",
|
||||
numberOfChannels: 1,
|
||||
frames: 30592,
|
||||
sampleRate: 44100,
|
||||
duration: 0.693,
|
||||
fuzzTolerance: 0,
|
||||
fuzzToleranceMobile: 0
|
||||
},
|
||||
{
|
||||
url: "ting-48k-1ch.wav",
|
||||
valid: true,
|
||||
expectedUrl: "ting-48k-1ch.wav",
|
||||
numberOfChannels: 1,
|
||||
frames: 33297,
|
||||
sampleRate: 48000,
|
||||
duration: 0.693,
|
||||
fuzzTolerance: 0,
|
||||
fuzzToleranceMobile: 0
|
||||
},
|
||||
// // A wave file
|
||||
// //{ url: "24bit-44khz.wav", valid: true, expectedUrl: "24bit-44khz-expected.wav" },
|
||||
// A non-audio file
|
||||
{ url: "invalid.txt", valid: false, sampleRate: 44100 },
|
||||
// A webm file with no audio
|
||||
{ url: "noaudio.webm", valid: false, sampleRate: 48000 },
|
||||
// A video ogg file with audio
|
||||
{
|
||||
url: "audio.ogv",
|
||||
valid: true,
|
||||
expectedUrl: "audio-expected.wav",
|
||||
numberOfChannels: 2,
|
||||
sampleRate: 44100,
|
||||
frames: 47680,
|
||||
duration: 1.0807,
|
||||
fuzzTolerance: 106,
|
||||
fuzzToleranceMobile: 3482
|
||||
}
|
||||
];
|
||||
|
||||
// Returns true if the memory buffers are less different that |fuzz| bytes
|
||||
function fuzzyMemcmp(buf1, buf2, fuzz) {
|
||||
var result = true;
|
||||
var difference = 0;
|
||||
is(buf1.length, buf2.length, "same length");
|
||||
for (var i = 0; i < buf1.length; ++i) {
|
||||
if (Math.abs(buf1[i] - buf2[i])) {
|
||||
++difference;
|
||||
}
|
||||
}
|
||||
if (difference > fuzz) {
|
||||
ok(false, "Expected at most " + fuzz + " bytes difference, found " + difference + " bytes");
|
||||
}
|
||||
return difference <= fuzz;
|
||||
}
|
||||
|
||||
function getFuzzTolerance(test) {
|
||||
var kIsMobile =
|
||||
navigator.userAgent.indexOf("Mobile") != -1 || // b2g
|
||||
navigator.userAgent.indexOf("Android") != -1; // android
|
||||
return kIsMobile ? test.fuzzToleranceMobile : test.fuzzTolerance;
|
||||
}
|
||||
|
||||
function bufferIsSilent(buffer) {
|
||||
for (var i = 0; i < buffer.length; ++i) {
|
||||
if (buffer.getChannelData(0)[i] != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkAudioBuffer(buffer, test) {
|
||||
if (buffer.numberOfChannels != test.numberOfChannels) {
|
||||
is(buffer.numberOfChannels, test.numberOfChannels, "Correct number of channels");
|
||||
return;
|
||||
}
|
||||
ok(Math.abs(buffer.duration - test.duration) < 1e-3, "Correct duration");
|
||||
if (Math.abs(buffer.duration - test.duration) >= 1e-3) {
|
||||
ok(false, "got: " + buffer.duration + ", expected: " + test.duration);
|
||||
}
|
||||
is(buffer.sampleRate, test.sampleRate, "Correct sample rate");
|
||||
is(buffer.length, test.frames, "Correct length");
|
||||
|
||||
var wave = createWaveFileData(buffer);
|
||||
ok(fuzzyMemcmp(wave, test.expectedWaveData, getFuzzTolerance(test)), "Received expected decoded data");
|
||||
}
|
||||
|
||||
function checkResampledBuffer(buffer, test, callback) {
|
||||
if (buffer.numberOfChannels != test.numberOfChannels) {
|
||||
is(buffer.numberOfChannels, test.numberOfChannels, "Correct number of channels");
|
||||
return;
|
||||
}
|
||||
ok(Math.abs(buffer.duration - test.duration) < 1e-3, "Correct duration");
|
||||
if (Math.abs(buffer.duration - test.duration) >= 1e-3) {
|
||||
ok(false, "got: " + buffer.duration + ", expected: " + test.duration);
|
||||
}
|
||||
// Take into account the resampling when checking the size
|
||||
var expectedLength = test.frames * buffer.sampleRate / test.sampleRate;
|
||||
ok(Math.abs(buffer.length - expectedLength) < 1.0, "Correct length", "got " + buffer.length + ", expected about " + expectedLength);
|
||||
|
||||
// Playback the buffer in the original context, to resample back to the
|
||||
// original rate and compare with the decoded buffer without resampling.
|
||||
cx = test.nativeContext;
|
||||
var expected = cx.createBufferSource();
|
||||
expected.buffer = test.expectedBuffer;
|
||||
expected.start();
|
||||
var inverse = cx.createGain();
|
||||
inverse.gain.value = -1;
|
||||
expected.connect(inverse);
|
||||
inverse.connect(cx.destination);
|
||||
var resampled = cx.createBufferSource();
|
||||
resampled.buffer = buffer;
|
||||
resampled.start();
|
||||
// This stop should do nothing, but it tests for bug 937475
|
||||
resampled.stop(test.frames / cx.sampleRate);
|
||||
resampled.connect(cx.destination);
|
||||
cx.oncomplete = function(e) {
|
||||
ok(!bufferIsSilent(e.renderedBuffer), "Expect buffer not silent");
|
||||
// Resampling will lose the highest frequency components, so we should
|
||||
// pass the difference through a low pass filter. However, either the
|
||||
// input files don't have significant high frequency components or the
|
||||
// tolerance in compareBuffers() is too high to detect them.
|
||||
compareBuffers(e.renderedBuffer,
|
||||
cx.createBuffer(test.numberOfChannels,
|
||||
test.frames, test.sampleRate));
|
||||
callback();
|
||||
}
|
||||
cx.startRendering();
|
||||
}
|
||||
|
||||
function runResampling(test, response, callback) {
|
||||
var sampleRate = test.sampleRate == 44100 ? 48000 : 44100;
|
||||
var cx = new OfflineAudioContext(1, 1, sampleRate);
|
||||
cx.decodeAudioData(response, function onSuccess(asyncResult) {
|
||||
is(asyncResult.sampleRate, sampleRate, "Correct sample rate");
|
||||
|
||||
checkResampledBuffer(asyncResult, test, callback);
|
||||
}, function onFailure() {
|
||||
ok(false, "Expected successful decode with resample");
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
function runTest(test, response, callback) {
|
||||
// We need to copy the array here, because decodeAudioData will detach the
|
||||
// array's buffer.
|
||||
var compressedAudio = response.slice(0);
|
||||
var expectCallback = false;
|
||||
var cx = new OfflineAudioContext(test.numberOfChannels || 1,
|
||||
test.frames || 1, test.sampleRate);
|
||||
cx.decodeAudioData(response, function onSuccess(asyncResult) {
|
||||
ok(expectCallback, "Success callback should fire asynchronously");
|
||||
ok(test.valid, "Did expect success for test " + test.url);
|
||||
|
||||
checkAudioBuffer(asyncResult, test);
|
||||
|
||||
test.expectedBuffer = asyncResult;
|
||||
test.nativeContext = cx;
|
||||
runResampling(test, compressedAudio, callback);
|
||||
}, function onFailure() {
|
||||
ok(expectCallback, "Failure callback should fire asynchronously");
|
||||
ok(!test.valid, "Did expect failure for test " + test.url);
|
||||
callback();
|
||||
});
|
||||
expectCallback = true;
|
||||
}
|
||||
|
||||
function loadTest(test, callback) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", test.url, true);
|
||||
xhr.responseType = "arraybuffer";
|
||||
xhr.onload = function() {
|
||||
var getExpected = new XMLHttpRequest();
|
||||
getExpected.open("GET", test.expectedUrl, true);
|
||||
getExpected.responseType = "arraybuffer";
|
||||
getExpected.onload = function() {
|
||||
test.expectedWaveData = new Uint8Array(getExpected.response);
|
||||
runTest(test, xhr.response, callback);
|
||||
};
|
||||
getExpected.send();
|
||||
};
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
function loadNextTest() {
|
||||
if (files.length) {
|
||||
loadTest(files.shift(), loadNextTest);
|
||||
} else {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
loadNextTest();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue