OLD | NEW |
1 <!doctype html> | 1 <!doctype html> |
2 <html> | 2 <html> |
3 <head> | 3 <head> |
4 <title>Test AudioContext.suspend() and AudioContext.resume()</title> | 4 <title>Test AudioContext.suspend() and AudioContext.resume()</title> |
5 <script src="../resources/js-test.js"></script> | 5 <script src="../resources/js-test.js"></script> |
6 <script src="resources/compatibility.js"></script> | 6 <script src="resources/compatibility.js"></script> |
7 <script src="resources/audio-testing.js"></script> | 7 <script src="resources/audio-testing.js"></script> |
8 </head> | 8 </head> |
9 | 9 |
10 <body> | 10 <body> |
11 <script> | 11 <script> |
12 description("Test suspend/resume for an AudioContext"); | 12 description("Test suspend/resume for an (offline) AudioContext"); |
13 window.jsTestIsAsync = true; | 13 window.jsTestIsAsync = true; |
14 | 14 |
15 var context = new AudioContext(); | 15 var offlineContext; |
| 16 var osc; |
| 17 var p1; |
| 18 var p2; |
| 19 var p3; |
| 20 |
| 21 var sampleRate = 44100; |
| 22 var durationInSeconds = 1; |
16 | 23 |
17 var audit = Audit.createTaskRunner(); | 24 var audit = Audit.createTaskRunner(); |
18 | 25 |
19 // Task: check the method interface. | 26 // Convenience function that returns a function that calls the |passFailFunc
| |
20 audit.defineTask('interface', function (done) { | 27 // with the given |message|. The |passFailFunc| should be either |testPasse
d| |
21 Should('typeof context.suspend()', typeof context.suspend).beEqualTo('func
tion'); | 28 // or |testFailed|. |
22 Should('typeof context.resume()', typeof context.resume).beEqualTo('functi
on'); | 29 function handlePromise(passFailFunc, message) { |
23 done(); | 30 return function () { |
| 31 passFailFunc(message); |
| 32 }; |
| 33 } |
| 34 |
| 35 // Task: test suspend(). |
| 36 audit.defineTask('test-suspend', function (done) { |
| 37 |
| 38 // Test suspend/resume. Ideally this test is best with a online |
| 39 // AudioContext, but content shell doesn't really have a working online |
| 40 // AudioContext. Hence, use an OfflineAudioContext. Not all possible |
| 41 // scenarios can be easily checked with an offline context instead of an |
| 42 // online context. |
| 43 |
| 44 // Create an audio context with an oscillator. |
| 45 shouldNotThrow("offlineContext = new OfflineAudioContext(1, durationInSeco
nds * sampleRate, sampleRate)"); |
| 46 osc = offlineContext.createOscillator(); |
| 47 osc.connect(offlineContext.destination); |
| 48 |
| 49 // Verify the state. |
| 50 shouldBeEqualToString("offlineContext.state", "suspended"); |
| 51 |
| 52 // Multiple calls to suspend() should not be a problem. But we can't test |
| 53 // that on an offline context. Thus, check that suspend() on an |
| 54 // OfflineAudioContext rejects the promise. |
| 55 shouldNotThrow("p1 = offlineContext.suspend()"); |
| 56 shouldBeType("p1", "Promise"); |
| 57 p1.then( |
| 58 handlePromise(testFailed, "offlineContext.suspend() should have been rej
ected for an offline context"), |
| 59 function (e) { |
| 60 if (e.name === "InvalidAccessError") { |
| 61 testPassed( |
| 62 "offlineContext.suspend() was correctly rejected: " + e); |
| 63 } else { |
| 64 testFailed( |
| 65 "offlineContext.suspend() was correctly rejected but expected Inva
lidAccessError, not: " + e); |
| 66 } |
| 67 } |
| 68 ).then(done); |
24 }); | 69 }); |
25 | 70 |
26 // Task: check the promise resolution. | |
27 audit.defineTask('promise-resolution', function (done) { | |
28 Should('context.suspend()', context.suspend()).beResolved().then(done); | |
29 | 71 |
30 // Resuming the context cannot be tested with the trybot or the Content | 72 // Task: test resume(). |
31 // Shell because it requires the physical audio device to run. | 73 audit.defineTask('test-resume', function (done) { |
| 74 |
| 75 // Multiple calls to resume should not be a problem. But we can't test |
| 76 // that on an offline context. Thus, check that resume() on an |
| 77 // OfflineAudioContext rejects the promise. |
| 78 shouldNotThrow("p2 = offlineContext.resume()"); |
| 79 shouldBeType("p2", "Promise"); |
| 80 |
| 81 // Resume doesn't actually resume an offline context |
| 82 shouldBeEqualToString("offlineContext.state", "suspended"); |
| 83 p2.then( |
| 84 handlePromise(testFailed, "offlineContext.resume() should have been reje
cted for an offline context"), |
| 85 function (e) { |
| 86 if (e.name === "InvalidAccessError") { |
| 87 testPassed( |
| 88 "offlineContext.resume() was correctly rejected: " + e); |
| 89 } else { |
| 90 testFailed( |
| 91 "offlineContext.resume() was correctly rejected but expected Inval
idAccessError, not: " + e); |
| 92 } |
| 93 } |
| 94 ).then(done); |
32 }); | 95 }); |
33 | 96 |
34 // Task: test corner cases. | 97 // Task: test the state after context closed. |
35 audit.defineTask('corner-cases', function (done) { | 98 audit.defineTask('test-after-close', function (done) { |
36 | 99 |
37 Should('Calling multiple context.suspend()', function() { | 100 // Render the offline context. |
38 context.suspend(); | 101 osc.start(); |
39 context.suspend(); | |
40 }).notThrow(); | |
41 | 102 |
42 context.close().then(function () { | 103 // Test suspend/resume in tested promise pattern. We don't care about the |
43 Should('Calling context.suspend() after close()', context.suspend()) | 104 // actual result of the offline rendering. |
44 .beRejected(); | 105 shouldNotThrow("p3 = offlineContext.startRendering()"); |
| 106 p3.then(function () { |
| 107 shouldBeEqualToString("offlineContext.state", "closed"); |
45 | 108 |
46 Should('Calling context.resume() after close()', context.resume()) | 109 // suspend() should be rejected on a closed context. |
47 .beRejected().then(done); | 110 offlineContext.suspend().then( |
| 111 handlePromise(testFailed, "offlineContext.suspend() on a closed contex
t not rejected"), |
| 112 function (e) { |
| 113 if (e.name === "InvalidAccessError") { |
| 114 testPassed("offlineContext.suspend() on a closed context rejected:
" + e); |
| 115 } else { |
| 116 testFailed("offlineContext.suspend() on a closed context rejected
but expected InvalidAccessError, not: " + e); |
| 117 } |
| 118 } |
| 119 ).then(function () { |
| 120 // resume() should be rejected on closed context. |
| 121 offlineContext.resume().then( |
| 122 handlePromise(testFailed, "offlineContext.resume() on a closed conte
xt not rejected"), |
| 123 function (e) { |
| 124 if (e.name === "InvalidAccessError") { |
| 125 testPassed("offlineContext.resume() on a closed context rejected
: " + e); |
| 126 } else { |
| 127 testFailed("offlineContext.resume() on a closed context rejected
but expected InvalidAccessError, not: " + e); |
| 128 } |
| 129 } |
| 130 ).then(done); |
| 131 }); |
| 132 |
48 }); | 133 }); |
49 | |
50 }); | 134 }); |
51 | 135 |
52 audit.defineTask('finish-test', function (done) { | 136 audit.defineTask('finish-test', function (done) { |
53 done(); | 137 done(); |
54 finishJSTest(); | 138 finishJSTest(); |
55 }); | 139 }); |
56 | 140 |
57 audit.runTasks( | 141 audit.runTasks( |
58 'interface', | 142 'test-suspend', |
59 'promise-resolution', | 143 'test-resume', |
60 'corner-cases', | 144 'test-after-close', |
61 'finish-test' | 145 'finish-test' |
62 ); | 146 ); |
63 | 147 |
64 successfullyParsed = true; | 148 successfullyParsed = true; |
65 </script> | 149 </script> |
66 </body> | 150 </body> |
67 </html> | 151 </html> |
OLD | NEW |