content/media/webaudio/test/webaudio.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/media/webaudio/test/webaudio.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,239 @@
     1.4 +// Helpers for Web Audio tests
     1.5 +
     1.6 +function expectException(func, exceptionCode) {
     1.7 +  var threw = false;
     1.8 +  try {
     1.9 +    func();
    1.10 +  } catch (ex) {
    1.11 +    threw = true;
    1.12 +    ok(ex instanceof DOMException, "Expect a DOM exception");
    1.13 +    is(ex.code, exceptionCode, "Expect the correct exception code");
    1.14 +  }
    1.15 +  ok(threw, "The exception was thrown");
    1.16 +}
    1.17 +
    1.18 +function expectNoException(func) {
    1.19 +  var threw = false;
    1.20 +  try {
    1.21 +    func();
    1.22 +  } catch (ex) {
    1.23 +    threw = true;
    1.24 +  }
    1.25 +  ok(!threw, "An exception was not thrown");
    1.26 +}
    1.27 +
    1.28 +function expectTypeError(func) {
    1.29 +  var threw = false;
    1.30 +  try {
    1.31 +    func();
    1.32 +  } catch (ex) {
    1.33 +    threw = true;
    1.34 +    ok(ex instanceof TypeError, "Expect a TypeError");
    1.35 +  }
    1.36 +  ok(threw, "The exception was thrown");
    1.37 +}
    1.38 +
    1.39 +function fuzzyCompare(a, b) {
    1.40 +  return Math.abs(a - b) < 9e-3;
    1.41 +}
    1.42 +
    1.43 +function compareChannels(buf1, buf2,
    1.44 +                        /*optional*/ length,
    1.45 +                        /*optional*/ sourceOffset,
    1.46 +                        /*optional*/ destOffset,
    1.47 +                        /*optional*/ skipLengthCheck) {
    1.48 +  if (!skipLengthCheck) {
    1.49 +    is(buf1.length, buf2.length, "Channels must have the same length");
    1.50 +  }
    1.51 +  sourceOffset = sourceOffset || 0;
    1.52 +  destOffset = destOffset || 0;
    1.53 +  if (length == undefined) {
    1.54 +    length = buf1.length - sourceOffset;
    1.55 +  }
    1.56 +  var difference = 0;
    1.57 +  var maxDifference = 0;
    1.58 +  var firstBadIndex = -1;
    1.59 +  for (var i = 0; i < length; ++i) {
    1.60 +    if (!fuzzyCompare(buf1[i + sourceOffset], buf2[i + destOffset])) {
    1.61 +      difference++;
    1.62 +      maxDifference = Math.max(maxDifference, Math.abs(buf1[i + sourceOffset] - buf2[i + destOffset]));
    1.63 +      if (firstBadIndex == -1) {
    1.64 +        firstBadIndex = i;
    1.65 +      }
    1.66 +    }
    1.67 +  };
    1.68 +
    1.69 +  is(difference, 0, "maxDifference: " + maxDifference +
    1.70 +     ", first bad index: " + firstBadIndex +
    1.71 +     " with test-data offset " + sourceOffset + " and expected-data offset " +
    1.72 +     destOffset + "; corresponding values " + buf1[firstBadIndex + sourceOffset] +
    1.73 +     " and " + buf2[firstBadIndex + destOffset] + " --- differences");
    1.74 +}
    1.75 +
    1.76 +function compareBuffers(got, expected) {
    1.77 +  if (got.numberOfChannels != expected.numberOfChannels) {
    1.78 +    is(got.numberOfChannels, expected.numberOfChannels,
    1.79 +       "Correct number of buffer channels");
    1.80 +    return;
    1.81 +  }
    1.82 +  if (got.length != expected.length) {
    1.83 +    is(got.length, expected.length,
    1.84 +       "Correct buffer length");
    1.85 +    return;
    1.86 +  }
    1.87 +  if (got.sampleRate != expected.sampleRate) {
    1.88 +    is(got.sampleRate, expected.sampleRate,
    1.89 +       "Correct sample rate");
    1.90 +    return;
    1.91 +  }
    1.92 +
    1.93 +  for (var i = 0; i < got.numberOfChannels; ++i) {
    1.94 +    compareChannels(got.getChannelData(i), expected.getChannelData(i),
    1.95 +                    got.length, 0, 0, true);
    1.96 +  }
    1.97 +}
    1.98 +
    1.99 +function getEmptyBuffer(context, length) {
   1.100 +  return context.createBuffer(gTest.numberOfChannels, length, context.sampleRate);
   1.101 +}
   1.102 +
   1.103 +/**
   1.104 + * This function assumes that the test file defines a single gTest variable with
   1.105 + * the following properties and methods:
   1.106 + *
   1.107 + * + numberOfChannels: optional property which specifies the number of channels
   1.108 + *                     in the output.  The default value is 2.
   1.109 + * + createGraph: mandatory method which takes a context object and does
   1.110 + *                everything needed in order to set up the Web Audio graph.
   1.111 + *                This function returns the node to be inspected.
   1.112 + * + createGraphAsync: async version of createGraph.  This function takes
   1.113 + *                     a callback which should be called with an argument
   1.114 + *                     set to the node to be inspected when the callee is
   1.115 + *                     ready to proceed with the test.  Either this function
   1.116 + *                     or createGraph must be provided.
   1.117 + * + createExpectedBuffers: optional method which takes a context object and
   1.118 + *                          returns either one expected buffer or an array of
   1.119 + *                          them, designating what is expected to be observed
   1.120 + *                          in the output.  If omitted, the output is expected
   1.121 + *                          to be silence.  All buffers must have the same
   1.122 + *                          length, which must be a bufferSize supported by
   1.123 + *                          ScriptProcessorNode.  This function is guaranteed
   1.124 + *                          to be called before createGraph.
   1.125 + * + length: property equal to the total number of frames which we are waiting
   1.126 + *           to see in the output, mandatory if createExpectedBuffers is not
   1.127 + *           provided, in which case it must be a bufferSize supported by
   1.128 + *           ScriptProcessorNode (256, 512, 1024, 2048, 4096, 8192, or 16384).
   1.129 + *           If createExpectedBuffers is provided then this must be equal to
   1.130 + *           the number of expected buffers * the expected buffer length.
   1.131 + *
   1.132 + * + skipOfflineContextTests: optional. when true, skips running tests on an offline
   1.133 + *                            context by circumventing testOnOfflineContext.
   1.134 + */
   1.135 +function runTest()
   1.136 +{
   1.137 +  function done() {
   1.138 +    SimpleTest.finish();
   1.139 +  }
   1.140 +
   1.141 +  SimpleTest.waitForExplicitFinish();
   1.142 +  function runTestFunction () {
   1.143 +    if (!gTest.numberOfChannels) {
   1.144 +      gTest.numberOfChannels = 2; // default
   1.145 +    }
   1.146 +
   1.147 +    var testLength;
   1.148 +
   1.149 +    function runTestOnContext(context, callback, testOutput) {
   1.150 +      if (!gTest.createExpectedBuffers) {
   1.151 +        // Assume that the output is silence
   1.152 +        var expectedBuffers = getEmptyBuffer(context, gTest.length);
   1.153 +      } else {
   1.154 +        var expectedBuffers = gTest.createExpectedBuffers(context);
   1.155 +      }
   1.156 +      if (!(expectedBuffers instanceof Array)) {
   1.157 +        expectedBuffers = [expectedBuffers];
   1.158 +      }
   1.159 +      var expectedFrames = 0;
   1.160 +      for (var i = 0; i < expectedBuffers.length; ++i) {
   1.161 +        is(expectedBuffers[i].numberOfChannels, gTest.numberOfChannels,
   1.162 +           "Correct number of channels for expected buffer " + i);
   1.163 +        expectedFrames += expectedBuffers[i].length;
   1.164 +      }
   1.165 +      if (gTest.length && gTest.createExpectedBuffers) {
   1.166 +        is(expectedFrames, gTest.length, "Correct number of expected frames");
   1.167 +      }
   1.168 +
   1.169 +      if (gTest.createGraphAsync) {
   1.170 +        gTest.createGraphAsync(context, function(nodeToInspect) {
   1.171 +          testOutput(nodeToInspect, expectedBuffers, callback);
   1.172 +        });
   1.173 +      } else {
   1.174 +        testOutput(gTest.createGraph(context), expectedBuffers, callback);
   1.175 +      }
   1.176 +    }
   1.177 +
   1.178 +    function testOnNormalContext(callback) {
   1.179 +      function testOutput(nodeToInspect, expectedBuffers, callback) {
   1.180 +        testLength = 0;
   1.181 +        var sp = context.createScriptProcessor(expectedBuffers[0].length, gTest.numberOfChannels);
   1.182 +        nodeToInspect.connect(sp);
   1.183 +        sp.connect(context.destination);
   1.184 +        sp.onaudioprocess = function(e) {
   1.185 +          var expectedBuffer = expectedBuffers.shift();
   1.186 +          testLength += expectedBuffer.length;
   1.187 +          compareBuffers(e.inputBuffer, expectedBuffer);
   1.188 +          if (expectedBuffers.length == 0) {
   1.189 +            sp.onaudioprocess = null;
   1.190 +            callback();
   1.191 +          }
   1.192 +        };
   1.193 +      }
   1.194 +      var context = new AudioContext();
   1.195 +      runTestOnContext(context, callback, testOutput);
   1.196 +    }
   1.197 +
   1.198 +    function testOnOfflineContext(callback, sampleRate) {
   1.199 +      function testOutput(nodeToInspect, expectedBuffers, callback) {
   1.200 +        nodeToInspect.connect(context.destination);
   1.201 +        context.oncomplete = function(e) {
   1.202 +          var samplesSeen = 0;
   1.203 +          while (expectedBuffers.length) {
   1.204 +            var expectedBuffer = expectedBuffers.shift();
   1.205 +            is(e.renderedBuffer.numberOfChannels, expectedBuffer.numberOfChannels,
   1.206 +               "Correct number of input buffer channels");
   1.207 +            for (var i = 0; i < e.renderedBuffer.numberOfChannels; ++i) {
   1.208 +              compareChannels(e.renderedBuffer.getChannelData(i),
   1.209 +                             expectedBuffer.getChannelData(i),
   1.210 +                             expectedBuffer.length,
   1.211 +                             samplesSeen,
   1.212 +                             undefined,
   1.213 +                             true);
   1.214 +            }
   1.215 +            samplesSeen += expectedBuffer.length;
   1.216 +          }
   1.217 +          callback();
   1.218 +        };
   1.219 +        context.startRendering();
   1.220 +      }
   1.221 +
   1.222 +      var context = new OfflineAudioContext(gTest.numberOfChannels, testLength, sampleRate);
   1.223 +      runTestOnContext(context, callback, testOutput);
   1.224 +    }
   1.225 +
   1.226 +    testOnNormalContext(function() {
   1.227 +      if (!gTest.skipOfflineContextTests) {
   1.228 +        testOnOfflineContext(function() {
   1.229 +          testOnOfflineContext(done, 44100);
   1.230 +        }, 48000);
   1.231 +      } else {
   1.232 +        done();
   1.233 +      }
   1.234 +    });
   1.235 +  };
   1.236 +
   1.237 +  if (document.readyState !== 'complete') {
   1.238 +    addLoadEvent(runTestFunction);
   1.239 +  } else {
   1.240 +    runTestFunction();
   1.241 +  }
   1.242 +}

mercurial