| <!DOCTYPE html> |
| <html> |
| <head> |
| <title> |
| offlineaudiocontext-suspend-resume-basic.html |
| </title> |
| <script src="../../imported/w3c/web-platform-tests/resources/testharness.js"></script> |
| <script src="../../resources/testharnessreport.js"></script> |
| <script src="../resources/audit-util.js"></script> |
| <script src="../resources/audit.js"></script> |
| </head> |
| <body> |
| <script id="layout-test-code"> |
| let sampleRate = 44100; |
| let renderDuration = 1; |
| let renderQuantum = 128; |
| |
| let audit = Audit.createTaskRunner(); |
| |
| // Task: Calling suspend with no argument, negative time or the time |
| // beyond the maximum render duration reject the promise. |
| audit.define('suspend-invalid-argument', (task, should) => { |
| let context = |
| new OfflineAudioContext(1, sampleRate * renderDuration, sampleRate); |
| |
| should(context.suspend(), 'context.suspend()').beRejected(); |
| should(context.suspend(-1.0), 'context.suspend(-1.0)').beRejected(); |
| should(context.suspend(2.0), 'context.suspend(2.0)').beRejected(); |
| |
| context.startRendering().then(() => task.done()); |
| }); |
| |
| // Task: Scheduling a suspend in the past should be rejected. |
| audit.define('suspend-in-the-past', (task, should) => { |
| let context = |
| new OfflineAudioContext(1, sampleRate * renderDuration, sampleRate); |
| |
| context.suspend(0.5).then(function() { |
| should( |
| context.suspend(context.currentTime - 0.1), |
| 'Scheduling a suspend in the past') |
| .beRejected(); |
| |
| should(context |
| .suspend( |
| context.currentTime + 0.1, |
| 'Scheduling a suspend in the future') |
| .then(function() { |
| context.resume(); |
| })) |
| .beResolved(); |
| |
| context.resume(); |
| }); |
| |
| context.startRendering().then(() => task.done()); |
| }); |
| |
| // Task: suspending after rendering is finished must be rejected with the |
| // properly clamped frame/time information. |
| audit.define('suspend-after-render-completion', (task, should) => { |
| let context = |
| new OfflineAudioContext(1, sampleRate * renderDuration, sampleRate); |
| context.startRendering() |
| .then(function() { |
| should( |
| context.suspend(renderDuration), |
| 'Scheduling a suspend after the render completion') |
| .beRejected(); |
| }) |
| .then(() => task.done()); |
| }); |
| |
| // Task: Calling multiple suspends at the same rendering quantum should |
| // reject the promise. |
| audit.define('identical-suspend-time', (task, should) => { |
| let context = |
| new OfflineAudioContext(1, sampleRate * renderDuration, sampleRate); |
| |
| // |suspendTime1| and |suspendTime2| are identical when quantized to the |
| // render quantum size. The factors are arbitrary except they should be |
| // between 1 (exclusive) and 2 (inclusive). Using a factor of 2 also |
| // tests that times are rounded up. |
| let suspendTime1 = 1.25 * renderQuantum / sampleRate; |
| let suspendTime2 = 2 * renderQuantum / sampleRate; |
| |
| should( |
| () => context.suspend(suspendTime1).then(() => context.resume()), |
| 'Scheduling a suspend at frame ' + suspendTime1 * sampleRate) |
| .notThrow(); |
| |
| should( |
| context.suspend(suspendTime2).then(() => context.resume()), |
| 'Scheduling another suspend at the same rendering quantum') |
| .beRejected(); |
| |
| context.startRendering().then(() => task.done()); |
| }); |
| |
| // Task: Resuming a running context should be resolved. |
| audit.define('resume-before-suspend', (task, should) => { |
| // Make the render length 5 times longer to minimize the flakiness. |
| let longRenderDuration = renderDuration * 5; |
| let context = new OfflineAudioContext( |
| 1, sampleRate * longRenderDuration, sampleRate); |
| |
| // Create dummy audio graph to slow the rendering. |
| let osc = context.createOscillator(); |
| let lpf = context.createBiquadFilter(); |
| osc.type = 'sawtooth'; |
| osc.frequency.setValueAtTime(0.1, 0.0); |
| osc.frequency.linearRampToValueAtTime(1000, longRenderDuration * 0.5); |
| osc.frequency.linearRampToValueAtTime(0.1, longRenderDuration); |
| lpf.frequency.setValueAtTime(0.1, 0.0); |
| lpf.frequency.linearRampToValueAtTime(1000, longRenderDuration * 0.5); |
| lpf.frequency.linearRampToValueAtTime(0.1, longRenderDuration); |
| osc.connect(lpf); |
| lpf.connect(context.destination); |
| osc.start(); |
| |
| // A suspend is scheduled at the 90% of the render duration. |
| should( |
| () => { |
| // Test is finished when this suspend resolves. |
| context.suspend(longRenderDuration * 0.9).then(() => task.done()); |
| }, |
| 'Scheduling a suspend at ' + longRenderDuration * 0.9 + ' seconds') |
| .notThrow(); |
| |
| // We have to start rendering to get the time running. |
| context.startRendering(); |
| |
| // Then call resume() immediately after the rendering starts. Resuming |
| // a context that is already running should be resolved. |
| should(context.resume(), 'Resuming a running context').beResolved(); |
| }); |
| |
| // Task: Calling resume on a context that is not started should reject the |
| // promise. |
| audit.define('resume-without-suspend', (task, should) => { |
| let context = |
| new OfflineAudioContext(1, sampleRate * renderDuration, sampleRate); |
| |
| should(context.resume(), 'Resuming a context without starting it') |
| .beRejected() |
| .then(() => task.done()); |
| }); |
| |
| audit.run(); |
| </script> |
| </body> |
| </html> |