LibWeb: Initialize OfflineAudioContext with correct defaults

This commit is contained in:
Tim Ledbetter 2025-01-07 23:24:10 +00:00 committed by Sam Atkins
commit 27dbe49f00
Notes: github-actions[bot] 2025-01-08 11:25:09 +00:00
11 changed files with 288 additions and 22 deletions

View file

@ -11,6 +11,7 @@
#include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
#include <LibWeb/HTML/Window.h>
#include <LibWeb/WebAudio/AudioContext.h>
#include <LibWeb/WebAudio/AudioDestinationNode.h>
#include <LibWeb/WebIDL/Promise.h>
namespace Web::WebAudio {
@ -20,7 +21,9 @@ GC_DEFINE_ALLOCATOR(AudioContext);
// https://webaudio.github.io/web-audio-api/#dom-audiocontext-audiocontext
WebIDL::ExceptionOr<GC::Ref<AudioContext>> AudioContext::construct_impl(JS::Realm& realm, AudioContextOptions const& context_options)
{
return realm.create<AudioContext>(realm, context_options);
auto context = realm.create<AudioContext>(realm, context_options);
context->m_destination = TRY(AudioDestinationNode::construct_impl(realm, context));
return context;
}
AudioContext::AudioContext(JS::Realm& realm, AudioContextOptions const& context_options)

View file

@ -17,8 +17,8 @@ namespace Web::WebAudio {
GC_DEFINE_ALLOCATOR(AudioDestinationNode);
AudioDestinationNode::AudioDestinationNode(JS::Realm& realm, GC::Ref<BaseAudioContext> context)
: AudioNode(realm, context)
AudioDestinationNode::AudioDestinationNode(JS::Realm& realm, GC::Ref<BaseAudioContext> 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> AudioDestinationNode::construct_impl(JS::Realm& realm, GC::Ref<BaseAudioContext> context)
WebIDL::ExceptionOr<GC::Ref<AudioDestinationNode>> AudioDestinationNode::construct_impl(JS::Realm& realm, GC::Ref<BaseAudioContext> context, WebIDL::UnsignedLong channel_count)
{
return realm.create<AudioDestinationNode>(realm, context);
auto node = realm.create<AudioDestinationNode>(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<void> 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:

View file

@ -27,10 +27,10 @@ public:
WebIDL::UnsignedLong number_of_outputs() override { return 1; }
WebIDL::ExceptionOr<void> set_channel_count(WebIDL::UnsignedLong) override;
static GC::Ref<AudioDestinationNode> construct_impl(JS::Realm&, GC::Ref<BaseAudioContext>);
static WebIDL::ExceptionOr<GC::Ref<AudioDestinationNode>> construct_impl(JS::Realm& realm, GC::Ref<BaseAudioContext> context, WebIDL::UnsignedLong channel_count = 2);
protected:
AudioDestinationNode(JS::Realm&, GC::Ref<BaseAudioContext>);
AudioDestinationNode(JS::Realm&, GC::Ref<BaseAudioContext>, WebIDL::UnsignedLong channel_count);
virtual void initialize(JS::Realm&) override;
virtual void visit_edges(Cell::Visitor&) override;

View file

@ -12,9 +12,10 @@ namespace Web::WebAudio {
GC_DEFINE_ALLOCATOR(AudioNode);
AudioNode::AudioNode(JS::Realm& realm, GC::Ref<BaseAudioContext> context)
AudioNode::AudioNode(JS::Realm& realm, GC::Ref<BaseAudioContext> context, WebIDL::UnsignedLong channel_count)
: DOM::EventTarget(realm)
, m_context(context)
, m_channel_count(channel_count)
{
}

View file

@ -71,7 +71,7 @@ public:
WebIDL::ExceptionOr<void> initialize_audio_node_options(AudioNodeOptions const& given_options, AudioNodeDefaultOptions const& default_options);
protected:
AudioNode(JS::Realm&, GC::Ref<BaseAudioContext>);
AudioNode(JS::Realm&, GC::Ref<BaseAudioContext>, WebIDL::UnsignedLong channel_count = 2);
virtual void initialize(JS::Realm&) override;
virtual void visit_edges(Cell::Visitor&) override;

View file

@ -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))
{

View file

@ -40,7 +40,7 @@ public:
static constexpr float MIN_SAMPLE_RATE { 8000 };
static constexpr float MAX_SAMPLE_RATE { 192000 };
GC::Ref<AudioDestinationNode> destination() const { return m_destination; }
GC::Ref<AudioDestinationNode> destination() const { return *m_destination; }
float sample_rate() const { return m_sample_rate; }
double current_time() const { return m_current_time; }
GC::Ref<AudioListener> 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<AudioDestinationNode> m_destination;
GC::Ptr<AudioDestinationNode> m_destination;
Vector<GC::Ref<WebIDL::Promise>> m_pending_promises;
private:

View file

@ -7,6 +7,7 @@
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/HTML/EventNames.h>
#include <LibWeb/HTML/Window.h>
#include <LibWeb/WebAudio/AudioDestinationNode.h>
#include <LibWeb/WebAudio/OfflineAudioContext.h>
namespace Web::WebAudio {
@ -26,7 +27,9 @@ WebIDL::ExceptionOr<GC::Ref<OfflineAudioContext>> 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<OfflineAudioContext>(realm, number_of_channels, length, sample_rate);
auto context = realm.create<OfflineAudioContext>(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<WebIDL::CallbackType> 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)

View file

@ -42,8 +42,7 @@ public:
void set_oncomplete(GC::Ptr<WebIDL::CallbackType>);
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;