diff --git a/Libraries/LibWeb/WebAudio/AudioBufferSourceNode.cpp b/Libraries/LibWeb/WebAudio/AudioBufferSourceNode.cpp index cebe94f64a2..461848fb7b9 100644 --- a/Libraries/LibWeb/WebAudio/AudioBufferSourceNode.cpp +++ b/Libraries/LibWeb/WebAudio/AudioBufferSourceNode.cpp @@ -110,9 +110,30 @@ double AudioBufferSourceNode::loop_end() const // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-start` WebIDL::ExceptionOr AudioBufferSourceNode::start(Optional when, Optional offset, Optional duration) { - (void)when; - (void)offset; - (void)duration; + // 1. If this AudioBufferSourceNode internal slot [[source started]] is true, an InvalidStateError exception MUST be thrown. + if (source_started()) + return WebIDL::InvalidStateError::create(realm(), "AudioBufferSourceNode has already been started"_string); + + // 2. Check for any errors that must be thrown due to parameter constraints described below. If any exception is thrown during this step, abort those steps. + // A RangeError exception MUST be thrown if when is negative. + if (when.has_value() && when.value() < 0) + return WebIDL::SimpleException { WebIDL::SimpleExceptionType::RangeError, "when must not be negative"sv }; + + // A RangeError exception MUST be thrown if offset is negative + if (offset.has_value() && offset.value() < 0) + return WebIDL::SimpleException { WebIDL::SimpleExceptionType::RangeError, "offset must not be negative"sv }; + + // A RangeError exception MUST be thrown if duration is negative. + if (duration.has_value() && duration.value() < 0) + return WebIDL::SimpleException { WebIDL::SimpleExceptionType::RangeError, "duration must not be negative"sv }; + + // 3. Set the internal slot [[source started]] on this AudioBufferSourceNode to true. + set_source_started(true); + + // FIXME: 4. Queue a control message to start the AudioBufferSourceNode, including the parameter values in the message. + // FIXME: 5. Acquire the contents of the buffer if the buffer has been set. + // FIXME: 6. Send a control message to the associated AudioContext to start running its rendering thread only when all the following conditions are met: + dbgln("FIXME: Implement AudioBufferSourceNode::start(when, offset, duration)"); return {}; } diff --git a/Libraries/LibWeb/WebAudio/AudioScheduledSourceNode.cpp b/Libraries/LibWeb/WebAudio/AudioScheduledSourceNode.cpp index 9d7653dd439..1b1e1cf666e 100644 --- a/Libraries/LibWeb/WebAudio/AudioScheduledSourceNode.cpp +++ b/Libraries/LibWeb/WebAudio/AudioScheduledSourceNode.cpp @@ -35,14 +35,38 @@ void AudioScheduledSourceNode::set_onended(GC::Ptr value) // https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-start WebIDL::ExceptionOr AudioScheduledSourceNode::start(double when) { - (void)when; + // 1. If this AudioScheduledSourceNode internal slot [[source started]] is true, an InvalidStateError exception MUST be thrown. + if (source_started()) + return WebIDL::InvalidStateError::create(realm(), "AudioScheduledSourceNode source has already started"_string); + + // 2. Check for any errors that must be thrown due to parameter constraints described below. If any exception is thrown during this step, abort those steps. + // A RangeError exception MUST be thrown if when is negative. + if (when < 0) + return WebIDL::SimpleException { WebIDL::SimpleExceptionType::RangeError, "when must not be negative"sv }; + + // 3. Set the internal slot [[source started]] on this AudioScheduledSourceNode to true. + set_source_started(true); + + // FIXME: 4. Queue a control message to start the AudioScheduledSourceNode, including the parameter values in the message. + // FIXME: 5. Send a control message to the associated AudioContext to start running its rendering thread only when all the following conditions are met: + return WebIDL::NotSupportedError::create(realm(), "FIXME: Implement AudioScheduledSourceNode::start"_string); } // https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-stop WebIDL::ExceptionOr AudioScheduledSourceNode::stop(double when) { - (void)when; + // 1. If this AudioScheduledSourceNode internal slot [[source started]] is not true, an InvalidStateError exception MUST be thrown. + if (!m_source_started) + return WebIDL::InvalidStateError::create(realm(), "AudioScheduledSourceNode source has not been started"_string); + + // 2. Check for any errors that must be thrown due to parameter constraints described below. + // A RangeError exception MUST be thrown if when is negative. + if (when < 0) + return WebIDL::SimpleException { WebIDL::SimpleExceptionType::RangeError, "when must not be negative"sv }; + + // FIXME: 3. Queue a control message to stop the AudioScheduledSourceNode, including the parameter values in the message. + return WebIDL::NotSupportedError::create(realm(), "FIXME: Implement AudioScheduledSourceNode::stop"_string); } diff --git a/Libraries/LibWeb/WebAudio/AudioScheduledSourceNode.h b/Libraries/LibWeb/WebAudio/AudioScheduledSourceNode.h index 66c10da9a7d..03e685c0eda 100644 --- a/Libraries/LibWeb/WebAudio/AudioScheduledSourceNode.h +++ b/Libraries/LibWeb/WebAudio/AudioScheduledSourceNode.h @@ -27,8 +27,15 @@ public: protected: AudioScheduledSourceNode(JS::Realm&, GC::Ref); + bool source_started() const { return m_source_started; } + void set_source_started(bool started) { m_source_started = started; } + virtual void initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; + +private: + // https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-source-started-slot + bool m_source_started { false }; }; } diff --git a/Tests/LibWeb/Text/expected/wpt-import/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-basic.txt b/Tests/LibWeb/Text/expected/wpt-import/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-basic.txt new file mode 100644 index 00000000000..4a8b124da43 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-basic.txt @@ -0,0 +1,23 @@ +Harness status: OK + +Found 18 tests + +18 Pass +Pass # AUDIT TASK RUNNER STARTED. +Pass Executing "start/stop exceptions" +Pass Audit report +Pass > [start/stop exceptions] +Pass start(NaN) threw TypeError: "Expected when to be a finite floating-point number". +Pass start(Infinity) threw TypeError: "Expected when to be a finite floating-point number". +Pass start(-Infinity) threw TypeError: "Expected when to be a finite floating-point number". +Pass Calling stop() before start() threw InvalidStateError: "AudioScheduledSourceNode source has not been started". +Pass start(-1) threw RangeError: "when must not be negative". +Pass start(0,-1) threw RangeError: "offset must not be negative". +Pass start(0,0,-1) threw RangeError: "duration must not be negative". +Pass Calling start() twice threw InvalidStateError: "AudioBufferSourceNode has already been started". +Pass stop(-1) threw RangeError: "when must not be negative". +Pass stop(NaN) threw TypeError: "Expected when to be a finite floating-point number". +Pass stop(Infinity) threw TypeError: "Expected when to be a finite floating-point number". +Pass stop(-Infinity) threw TypeError: "Expected when to be a finite floating-point number". +Pass < [start/stop exceptions] All assertions passed. (total 12 assertions) +Pass # AUDIT TASK RUNNER FINISHED: 1 tasks ran successfully. \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/wpt-import/webaudio/resources/start-stop-exceptions.js b/Tests/LibWeb/Text/input/wpt-import/webaudio/resources/start-stop-exceptions.js new file mode 100644 index 00000000000..0d2ea12f6db --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/webaudio/resources/start-stop-exceptions.js @@ -0,0 +1,45 @@ +// Test that exceptions are throw for invalid values for start and +// stop. +function testStartStop(should, node, options) { + // Test non-finite values for start. These should all throw a TypeError + const nonFiniteValues = [NaN, Infinity, -Infinity]; + + nonFiniteValues.forEach(time => { + should(() => { + node.start(time); + }, `start(${time})`) + .throw(TypeError); + }); + + should(() => { + node.stop(); + }, 'Calling stop() before start()').throw(DOMException, 'InvalidStateError'); + + should(() => { + node.start(-1); + }, 'start(-1)').throw(RangeError); + + if (options) { + options.forEach(test => { + should(() => {node.start(...test.args)}, + 'start(' + test.args + ')').throw(test.errorType); + }); + } + + node.start(); + should(() => { + node.start(); + }, 'Calling start() twice').throw(DOMException, 'InvalidStateError'); + should(() => { + node.stop(-1); + }, 'stop(-1)').throw(RangeError); + + // Test non-finite stop times + nonFiniteValues.forEach(time => { + should(() => { + node.stop(time); + }, `stop(${time})`) + .throw(TypeError); + }); +} + diff --git a/Tests/LibWeb/Text/input/wpt-import/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-basic.html b/Tests/LibWeb/Text/input/wpt-import/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-basic.html new file mode 100644 index 00000000000..47cd07a4f10 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-basic.html @@ -0,0 +1,37 @@ + + + + + Basic Test of AudioBufferSourceNode + + + + + + + + + + +