LibWeb/WebAudio: Fire complete event with OfflineAudioCompletionEvent

This commit is contained in:
Luke Wilde 2025-11-18 16:49:02 +00:00 committed by Andreas Kling
parent 556699d601
commit 47b512ec56
Notes: github-actions[bot] 2025-11-19 16:27:18 +00:00
9 changed files with 120 additions and 14 deletions

View file

@ -1013,6 +1013,7 @@ set(SOURCES
WebAudio/DynamicsCompressorNode.cpp WebAudio/DynamicsCompressorNode.cpp
WebAudio/GainNode.cpp WebAudio/GainNode.cpp
WebAudio/MediaElementAudioSourceNode.cpp WebAudio/MediaElementAudioSourceNode.cpp
WebAudio/OfflineAudioCompletionEvent.cpp
WebAudio/OfflineAudioContext.cpp WebAudio/OfflineAudioContext.cpp
WebAudio/OscillatorNode.cpp WebAudio/OscillatorNode.cpp
WebAudio/PannerNode.cpp WebAudio/PannerNode.cpp

View file

@ -1203,6 +1203,7 @@ class BaseAudioContext;
class BiquadFilterNode; class BiquadFilterNode;
class DynamicsCompressorNode; class DynamicsCompressorNode;
class GainNode; class GainNode;
class OfflineAudioCompletionEvent;
class OfflineAudioContext; class OfflineAudioContext;
class OscillatorNode; class OscillatorNode;
class PannerNode; class PannerNode;

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2025, Luke Wilde <luke@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Bindings/OfflineAudioCompletionEventPrototype.h>
#include <LibWeb/WebAudio/OfflineAudioCompletionEvent.h>
namespace Web::WebAudio {
GC_DEFINE_ALLOCATOR(OfflineAudioCompletionEvent);
WebIDL::ExceptionOr<GC::Ref<OfflineAudioCompletionEvent>> OfflineAudioCompletionEvent::construct_impl(JS::Realm& realm, FlyString const& event_name, OfflineAudioCompletionEventInit const& event_init)
{
return realm.create<OfflineAudioCompletionEvent>(realm, event_name, event_init);
}
OfflineAudioCompletionEvent::OfflineAudioCompletionEvent(JS::Realm& realm, FlyString const& event_name, OfflineAudioCompletionEventInit const& event_init)
: DOM::Event(realm, event_name, event_init)
, m_rendered_buffer(event_init.rendered_buffer)
{
}
OfflineAudioCompletionEvent::~OfflineAudioCompletionEvent() = default;
void OfflineAudioCompletionEvent::initialize(JS::Realm& realm)
{
WEB_SET_PROTOTYPE_FOR_INTERFACE(OfflineAudioCompletionEvent);
Base::initialize(realm);
}
void OfflineAudioCompletionEvent::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_rendered_buffer);
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2025, Luke Wilde <luke@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibWeb/DOM/Event.h>
#include <LibWeb/WebAudio/AudioBuffer.h>
namespace Web::WebAudio {
struct OfflineAudioCompletionEventInit : public DOM::EventInit {
GC::Ptr<AudioBuffer> rendered_buffer;
};
class OfflineAudioCompletionEvent final : public DOM::Event {
WEB_PLATFORM_OBJECT(OfflineAudioCompletionEvent, DOM::Event);
GC_DECLARE_ALLOCATOR(OfflineAudioCompletionEvent);
public:
static WebIDL::ExceptionOr<GC::Ref<OfflineAudioCompletionEvent>> construct_impl(JS::Realm&, FlyString const& event_name, OfflineAudioCompletionEventInit const& event_init);
virtual ~OfflineAudioCompletionEvent() override;
GC::Ptr<AudioBuffer> rendered_buffer() const { return m_rendered_buffer; }
private:
OfflineAudioCompletionEvent(JS::Realm&, FlyString const& event_name, OfflineAudioCompletionEventInit const& event_init);
void initialize(JS::Realm&) override;
virtual void visit_edges(Cell::Visitor&) override;
GC::Ptr<AudioBuffer> m_rendered_buffer;
};
}

View file

@ -0,0 +1,14 @@
#import <DOM/Event.idl>
#import <WebAudio/AudioBuffer.idl>
// https://webaudio.github.io/web-audio-api/#OfflineAudioCompletionEvent
[Exposed=Window]
interface OfflineAudioCompletionEvent : Event {
constructor(DOMString type, OfflineAudioCompletionEventInit eventInitDict);
readonly attribute AudioBuffer renderedBuffer;
};
// https://webaudio.github.io/web-audio-api/#OfflineAudioCompletionEventInit
dictionary OfflineAudioCompletionEventInit : EventInit {
required AudioBuffer renderedBuffer;
};

View file

@ -13,6 +13,7 @@
#include <LibWeb/HTML/Window.h> #include <LibWeb/HTML/Window.h>
#include <LibWeb/WebAudio/AudioBuffer.h> #include <LibWeb/WebAudio/AudioBuffer.h>
#include <LibWeb/WebAudio/AudioDestinationNode.h> #include <LibWeb/WebAudio/AudioDestinationNode.h>
#include <LibWeb/WebAudio/OfflineAudioCompletionEvent.h>
#include <LibWeb/WebAudio/OfflineAudioContext.h> #include <LibWeb/WebAudio/OfflineAudioContext.h>
namespace Web::WebAudio { namespace Web::WebAudio {
@ -138,9 +139,17 @@ void OfflineAudioContext::begin_offline_rendering(GC::Ref<WebIDL::Promise> promi
// 4.2: Queue a media element task to fire an event named complete at the OfflineAudioContext using OfflineAudioCompletionEvent // 4.2: Queue a media element task to fire an event named complete at the OfflineAudioContext using OfflineAudioCompletionEvent
// whose renderedBuffer property is set to [[rendered buffer]]. // whose renderedBuffer property is set to [[rendered buffer]].
// FIXME: Need to implement OfflineAudioCompletionEvent.
queue_a_media_element_task(GC::create_function(heap(), [&realm, this]() { queue_a_media_element_task(GC::create_function(heap(), [&realm, this]() {
this->dispatch_event(DOM::Event::create(realm, HTML::EventNames::complete)); auto event_init = OfflineAudioCompletionEventInit {
{
.bubbles = false,
.cancelable = false,
.composed = false,
},
this->m_rendered_buffer,
};
auto event = MUST(OfflineAudioCompletionEvent::construct_impl(realm, HTML::EventNames::complete, event_init));
this->dispatch_event(event);
})); }));
})); }));
} }

View file

@ -473,6 +473,7 @@ libweb_js_bindings(WebAudio/ConstantSourceNode)
libweb_js_bindings(WebAudio/DelayNode) libweb_js_bindings(WebAudio/DelayNode)
libweb_js_bindings(WebAudio/GainNode) libweb_js_bindings(WebAudio/GainNode)
libweb_js_bindings(WebAudio/MediaElementAudioSourceNode) libweb_js_bindings(WebAudio/MediaElementAudioSourceNode)
libweb_js_bindings(WebAudio/OfflineAudioCompletionEvent)
libweb_js_bindings(WebAudio/OfflineAudioContext) libweb_js_bindings(WebAudio/OfflineAudioContext)
libweb_js_bindings(WebAudio/OscillatorNode) libweb_js_bindings(WebAudio/OscillatorNode)
libweb_js_bindings(WebAudio/PannerNode) libweb_js_bindings(WebAudio/PannerNode)

View file

@ -317,6 +317,7 @@ NodeList
Notification Notification
Number Number
Object Object
OfflineAudioCompletionEvent
OfflineAudioContext OfflineAudioContext
OffscreenCanvas OffscreenCanvas
OffscreenCanvasRenderingContext2D OffscreenCanvasRenderingContext2D

View file

@ -2,8 +2,8 @@ Harness status: OK
Found 1147 tests Found 1147 tests
882 Pass 892 Pass
265 Fail 255 Fail
Fail idl_test setup Fail idl_test setup
Pass idl_test validation Pass idl_test validation
Pass Partial interface Element: member names are unique Pass Partial interface Element: member names are unique
@ -184,16 +184,16 @@ Pass BaseAudioContext interface: new OfflineAudioContext(1, 1, sample_rate) must
Fail BaseAudioContext interface: new OfflineAudioContext(1, 1, sample_rate) must inherit property "createWaveShaper()" with the proper type Fail BaseAudioContext interface: new OfflineAudioContext(1, 1, sample_rate) must inherit property "createWaveShaper()" with the proper type
Pass BaseAudioContext interface: new OfflineAudioContext(1, 1, sample_rate) must inherit property "decodeAudioData(ArrayBuffer, optional DecodeSuccessCallback?, optional DecodeErrorCallback?)" with the proper type Pass BaseAudioContext interface: new OfflineAudioContext(1, 1, sample_rate) must inherit property "decodeAudioData(ArrayBuffer, optional DecodeSuccessCallback?, optional DecodeErrorCallback?)" with the proper type
Pass BaseAudioContext interface: calling decodeAudioData(ArrayBuffer, optional DecodeSuccessCallback?, optional DecodeErrorCallback?) on new OfflineAudioContext(1, 1, sample_rate) with too few arguments must throw TypeError Pass BaseAudioContext interface: calling decodeAudioData(ArrayBuffer, optional DecodeSuccessCallback?, optional DecodeErrorCallback?) on new OfflineAudioContext(1, 1, sample_rate) with too few arguments must throw TypeError
Fail OfflineAudioCompletionEvent interface: existence and properties of interface object Pass OfflineAudioCompletionEvent interface: existence and properties of interface object
Fail OfflineAudioCompletionEvent interface object length Pass OfflineAudioCompletionEvent interface object length
Fail OfflineAudioCompletionEvent interface object name Pass OfflineAudioCompletionEvent interface object name
Fail OfflineAudioCompletionEvent interface: existence and properties of interface prototype object Pass OfflineAudioCompletionEvent interface: existence and properties of interface prototype object
Fail OfflineAudioCompletionEvent interface: existence and properties of interface prototype object's "constructor" property Pass OfflineAudioCompletionEvent interface: existence and properties of interface prototype object's "constructor" property
Fail OfflineAudioCompletionEvent interface: existence and properties of interface prototype object's @@unscopables property Pass OfflineAudioCompletionEvent interface: existence and properties of interface prototype object's @@unscopables property
Fail OfflineAudioCompletionEvent interface: attribute renderedBuffer Pass OfflineAudioCompletionEvent interface: attribute renderedBuffer
Fail OfflineAudioCompletionEvent must be primary interface of new OfflineAudioCompletionEvent("", {renderedBuffer: buffer}) Pass OfflineAudioCompletionEvent must be primary interface of new OfflineAudioCompletionEvent("", {renderedBuffer: buffer})
Fail Stringification of new OfflineAudioCompletionEvent("", {renderedBuffer: buffer}) Pass Stringification of new OfflineAudioCompletionEvent("", {renderedBuffer: buffer})
Fail OfflineAudioCompletionEvent interface: new OfflineAudioCompletionEvent("", {renderedBuffer: buffer}) must inherit property "renderedBuffer" with the proper type Pass OfflineAudioCompletionEvent interface: new OfflineAudioCompletionEvent("", {renderedBuffer: buffer}) must inherit property "renderedBuffer" with the proper type
Pass AudioBuffer interface: existence and properties of interface object Pass AudioBuffer interface: existence and properties of interface object
Pass AudioBuffer interface object length Pass AudioBuffer interface object length
Pass AudioBuffer interface object name Pass AudioBuffer interface object name