diff --git a/Libraries/LibWeb/WebAudio/AudioContext.cpp b/Libraries/LibWeb/WebAudio/AudioContext.cpp index d90ca6dec65..68f88911b0f 100644 --- a/Libraries/LibWeb/WebAudio/AudioContext.cpp +++ b/Libraries/LibWeb/WebAudio/AudioContext.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include namespace Web::WebAudio { @@ -20,7 +21,9 @@ GC_DEFINE_ALLOCATOR(AudioContext); // https://webaudio.github.io/web-audio-api/#dom-audiocontext-audiocontext WebIDL::ExceptionOr> AudioContext::construct_impl(JS::Realm& realm, AudioContextOptions const& context_options) { - return realm.create(realm, context_options); + auto context = realm.create(realm, context_options); + context->m_destination = TRY(AudioDestinationNode::construct_impl(realm, context)); + return context; } AudioContext::AudioContext(JS::Realm& realm, AudioContextOptions const& context_options) diff --git a/Libraries/LibWeb/WebAudio/AudioDestinationNode.cpp b/Libraries/LibWeb/WebAudio/AudioDestinationNode.cpp index 869aa4f0c19..13cceefaebb 100644 --- a/Libraries/LibWeb/WebAudio/AudioDestinationNode.cpp +++ b/Libraries/LibWeb/WebAudio/AudioDestinationNode.cpp @@ -17,8 +17,8 @@ namespace Web::WebAudio { GC_DEFINE_ALLOCATOR(AudioDestinationNode); -AudioDestinationNode::AudioDestinationNode(JS::Realm& realm, GC::Ref context) - : AudioNode(realm, context) +AudioDestinationNode::AudioDestinationNode(JS::Realm& realm, GC::Ref context, WebIDL::UnsignedLong channel_count) + : AudioNode(realm, context, channel_count) { } @@ -31,9 +31,21 @@ WebIDL::UnsignedLong AudioDestinationNode::max_channel_count() return 2; } -GC::Ref AudioDestinationNode::construct_impl(JS::Realm& realm, GC::Ref context) +WebIDL::ExceptionOr> AudioDestinationNode::construct_impl(JS::Realm& realm, GC::Ref context, WebIDL::UnsignedLong channel_count) { - return realm.create(realm, context); + auto node = realm.create(realm, context, channel_count); + + // Default options for channel count and interpretation + // https://webaudio.github.io/web-audio-api/#AudioDestinationNode + AudioNodeDefaultOptions default_options; + default_options.channel_count_mode = Bindings::ChannelCountMode::Explicit; + default_options.channel_interpretation = Bindings::ChannelInterpretation::Speakers; + default_options.channel_count = channel_count; + // FIXME: Set tail-time to no + + TRY(node->initialize_audio_node_options({}, default_options)); + + return node; } void AudioDestinationNode::initialize(JS::Realm& realm) @@ -50,6 +62,9 @@ void AudioDestinationNode::visit_edges(Cell::Visitor& visitor) // https://webaudio.github.io/web-audio-api/#dom-audionode-channelcount WebIDL::ExceptionOr AudioDestinationNode::set_channel_count(WebIDL::UnsignedLong channel_count) { + if (channel_count == this->channel_count()) + return {}; + // The behavior depends on whether the destination node is the destination of an AudioContext // or OfflineAudioContext: diff --git a/Libraries/LibWeb/WebAudio/AudioDestinationNode.h b/Libraries/LibWeb/WebAudio/AudioDestinationNode.h index 25cea0576c3..453c4111095 100644 --- a/Libraries/LibWeb/WebAudio/AudioDestinationNode.h +++ b/Libraries/LibWeb/WebAudio/AudioDestinationNode.h @@ -27,10 +27,10 @@ public: WebIDL::UnsignedLong number_of_outputs() override { return 1; } WebIDL::ExceptionOr set_channel_count(WebIDL::UnsignedLong) override; - static GC::Ref construct_impl(JS::Realm&, GC::Ref); + static WebIDL::ExceptionOr> construct_impl(JS::Realm& realm, GC::Ref context, WebIDL::UnsignedLong channel_count = 2); protected: - AudioDestinationNode(JS::Realm&, GC::Ref); + AudioDestinationNode(JS::Realm&, GC::Ref, WebIDL::UnsignedLong channel_count); virtual void initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; diff --git a/Libraries/LibWeb/WebAudio/AudioNode.cpp b/Libraries/LibWeb/WebAudio/AudioNode.cpp index 13b27f355b3..6ce11238bb9 100644 --- a/Libraries/LibWeb/WebAudio/AudioNode.cpp +++ b/Libraries/LibWeb/WebAudio/AudioNode.cpp @@ -12,9 +12,10 @@ namespace Web::WebAudio { GC_DEFINE_ALLOCATOR(AudioNode); -AudioNode::AudioNode(JS::Realm& realm, GC::Ref context) +AudioNode::AudioNode(JS::Realm& realm, GC::Ref context, WebIDL::UnsignedLong channel_count) : DOM::EventTarget(realm) , m_context(context) + , m_channel_count(channel_count) { } diff --git a/Libraries/LibWeb/WebAudio/AudioNode.h b/Libraries/LibWeb/WebAudio/AudioNode.h index 90736361423..4509c87bd69 100644 --- a/Libraries/LibWeb/WebAudio/AudioNode.h +++ b/Libraries/LibWeb/WebAudio/AudioNode.h @@ -71,7 +71,7 @@ public: WebIDL::ExceptionOr initialize_audio_node_options(AudioNodeOptions const& given_options, AudioNodeDefaultOptions const& default_options); protected: - AudioNode(JS::Realm&, GC::Ref); + AudioNode(JS::Realm&, GC::Ref, WebIDL::UnsignedLong channel_count = 2); virtual void initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; diff --git a/Libraries/LibWeb/WebAudio/BaseAudioContext.cpp b/Libraries/LibWeb/WebAudio/BaseAudioContext.cpp index 59994aa216d..e4bd3cf7e9b 100644 --- a/Libraries/LibWeb/WebAudio/BaseAudioContext.cpp +++ b/Libraries/LibWeb/WebAudio/BaseAudioContext.cpp @@ -28,7 +28,6 @@ namespace Web::WebAudio { BaseAudioContext::BaseAudioContext(JS::Realm& realm, float sample_rate) : DOM::EventTarget(realm) - , m_destination(AudioDestinationNode::construct_impl(realm, *this)) , m_sample_rate(sample_rate) , m_listener(AudioListener::create(realm)) { diff --git a/Libraries/LibWeb/WebAudio/BaseAudioContext.h b/Libraries/LibWeb/WebAudio/BaseAudioContext.h index ea50a48b77b..a2d05032593 100644 --- a/Libraries/LibWeb/WebAudio/BaseAudioContext.h +++ b/Libraries/LibWeb/WebAudio/BaseAudioContext.h @@ -40,7 +40,7 @@ public: static constexpr float MIN_SAMPLE_RATE { 8000 }; static constexpr float MAX_SAMPLE_RATE { 192000 }; - GC::Ref destination() const { return m_destination; } + GC::Ref destination() const { return *m_destination; } float sample_rate() const { return m_sample_rate; } double current_time() const { return m_current_time; } GC::Ref listener() const { return m_listener; } @@ -80,7 +80,7 @@ protected: virtual void initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; - GC::Ref m_destination; + GC::Ptr m_destination; Vector> m_pending_promises; private: diff --git a/Libraries/LibWeb/WebAudio/OfflineAudioContext.cpp b/Libraries/LibWeb/WebAudio/OfflineAudioContext.cpp index 5393eca4e9c..16634710b95 100644 --- a/Libraries/LibWeb/WebAudio/OfflineAudioContext.cpp +++ b/Libraries/LibWeb/WebAudio/OfflineAudioContext.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include namespace Web::WebAudio { @@ -26,7 +27,9 @@ WebIDL::ExceptionOr> OfflineAudioContext::construct // A NotSupportedError exception MUST be thrown if any of the arguments is negative, zero, or outside its nominal range. TRY(verify_audio_options_inside_nominal_range(realm, number_of_channels, length, sample_rate)); - return realm.create(realm, number_of_channels, length, sample_rate); + auto context = realm.create(realm, length, sample_rate); + context->m_destination = TRY(AudioDestinationNode::construct_impl(realm, context, number_of_channels)); + return context; } OfflineAudioContext::~OfflineAudioContext() = default; @@ -67,16 +70,10 @@ void OfflineAudioContext::set_oncomplete(GC::Ptr value) set_event_handler_attribute(HTML::EventNames::complete, value); } -OfflineAudioContext::OfflineAudioContext(JS::Realm& realm, OfflineAudioContextOptions const&) - : BaseAudioContext(realm) -{ -} - -OfflineAudioContext::OfflineAudioContext(JS::Realm& realm, WebIDL::UnsignedLong number_of_channels, WebIDL::UnsignedLong length, float sample_rate) +OfflineAudioContext::OfflineAudioContext(JS::Realm& realm, WebIDL::UnsignedLong length, float sample_rate) : BaseAudioContext(realm, sample_rate) , m_length(length) { - (void)number_of_channels; } void OfflineAudioContext::initialize(JS::Realm& realm) diff --git a/Libraries/LibWeb/WebAudio/OfflineAudioContext.h b/Libraries/LibWeb/WebAudio/OfflineAudioContext.h index 63c6b8e0cc0..4eec6eb5b66 100644 --- a/Libraries/LibWeb/WebAudio/OfflineAudioContext.h +++ b/Libraries/LibWeb/WebAudio/OfflineAudioContext.h @@ -42,8 +42,7 @@ public: void set_oncomplete(GC::Ptr); private: - OfflineAudioContext(JS::Realm&, OfflineAudioContextOptions const&); - OfflineAudioContext(JS::Realm&, WebIDL::UnsignedLong number_of_channels, WebIDL::UnsignedLong length, float sample_rate); + OfflineAudioContext(JS::Realm&, WebIDL::UnsignedLong length, float sample_rate); virtual void initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; diff --git a/Tests/LibWeb/Text/expected/wpt-import/webaudio/the-audio-api/the-offlineaudiocontext-interface/ctor-offlineaudiocontext.txt b/Tests/LibWeb/Text/expected/wpt-import/webaudio/the-audio-api/the-offlineaudiocontext-interface/ctor-offlineaudiocontext.txt new file mode 100644 index 00000000000..3603f464afd --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/webaudio/the-audio-api/the-offlineaudiocontext-interface/ctor-offlineaudiocontext.txt @@ -0,0 +1,49 @@ +Harness status: OK + +Found 44 tests + +44 Pass +Pass # AUDIT TASK RUNNER STARTED. +Pass Executing "basic" +Pass Executing "options-1" +Pass Executing "options-2" +Pass Executing "options-3" +Pass Audit report +Pass > [basic] Old-style constructor +Pass new OfflineAudioContext(3) threw TypeError: "Not an object of type OfflineAudioContextOptions". +Pass new OfflineAudioContext(3, 42) threw TypeError: "Overload resolution failed". +Pass context = new OfflineAudioContext(3, 42, 12345) did not throw an exception. +Pass context.length is equal to 42. +Pass context.sampleRate is equal to 12345. +Pass context.destination.channelCount is equal to 3. +Pass context.destination.channelCountMode is equal to explicit. +Pass context.destination.channelInterpretation is equal to speakers. +Pass < [basic] All assertions passed. (total 8 assertions) +Pass > [options-1] Required options +Pass new OfflineAudioContext() threw TypeError: "Overload resolution failed". +Pass new OfflineAudioContext({}) threw TypeError: "Required property length is missing or undefined". +Pass new OfflineAudioContext({"length":42}) threw TypeError: "Required property sampleRate is missing or undefined". +Pass new OfflineAudioContext({"sampleRate":12345}) threw TypeError: "Required property length is missing or undefined". +Pass c2 = new OfflineAudioContext({"length":42,"sampleRate":12345}) did not throw an exception. +Pass c2.destination.channelCount is equal to 1. +Pass c2.length is equal to 42. +Pass c2.sampleRate is equal to 12345. +Pass c2.destination.channelCountMode is equal to explicit. +Pass c2.destination.channelInterpretation is equal to speakers. +Pass < [options-1] All assertions passed. (total 10 assertions) +Pass > [options-2] Invalid options +Pass new OfflineAudioContext({"length":42,"sampleRate":8000,"numberOfChannels":33}) threw NotSupportedError: "Number of channels is greater than allowed range". +Pass new OfflineAudioContext({"length":0,"sampleRate":8000}) threw NotSupportedError: "Length of buffer must be at least 1". +Pass new OfflineAudioContext({"length":1,"sampleRate":1}) threw NotSupportedError: "Sample rate is outside of allowed range". +Pass < [options-2] All assertions passed. (total 3 assertions) +Pass > [options-3] Valid options +Pass c = new OfflineAudioContext{"length":1,"sampleRate":8000}) did not throw an exception. +Pass c.length is equal to 1. +Pass c.sampleRate is equal to 8000. +Pass c.destination.channelCount is equal to 1. +Pass c.destination.channelCountMode is equal to explicit. +Pass c.destination.channelCountMode is equal to speakers. +Pass c = new OfflineAudioContext{"length":1,"sampleRate":8000,"numberOfChannels":7}) did not throw an exception. +Pass c.destination.channelCount is equal to 7. +Pass < [options-3] All assertions passed. (total 8 assertions) +Pass # AUDIT TASK RUNNER FINISHED: 4 tasks ran successfully. \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/wpt-import/webaudio/the-audio-api/the-offlineaudiocontext-interface/ctor-offlineaudiocontext.html b/Tests/LibWeb/Text/input/wpt-import/webaudio/the-audio-api/the-offlineaudiocontext-interface/ctor-offlineaudiocontext.html new file mode 100644 index 00000000000..22b18328fd7 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/webaudio/the-audio-api/the-offlineaudiocontext-interface/ctor-offlineaudiocontext.html @@ -0,0 +1,203 @@ + + + + Test Constructor: OfflineAudioContext + + + + + + + + + + +