Coverage Report

Created: 2025-09-05 06:52

/src/serenity/Userland/Libraries/LibWeb/HTML/AudioTrack.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#include <AK/IDAllocator.h>
8
#include <LibAudio/Loader.h>
9
#include <LibJS/Runtime/Realm.h>
10
#include <LibJS/Runtime/VM.h>
11
#include <LibWeb/Bindings/AudioTrackPrototype.h>
12
#include <LibWeb/Bindings/Intrinsics.h>
13
#include <LibWeb/DOM/Event.h>
14
#include <LibWeb/HTML/AudioTrack.h>
15
#include <LibWeb/HTML/AudioTrackList.h>
16
#include <LibWeb/HTML/EventNames.h>
17
#include <LibWeb/HTML/HTMLMediaElement.h>
18
#include <LibWeb/Layout/Node.h>
19
#include <LibWeb/Painting/Paintable.h>
20
#include <LibWeb/Platform/AudioCodecPlugin.h>
21
22
namespace Web::HTML {
23
24
JS_DEFINE_ALLOCATOR(AudioTrack);
25
26
static IDAllocator s_audio_track_id_allocator;
27
28
AudioTrack::AudioTrack(JS::Realm& realm, JS::NonnullGCPtr<HTMLMediaElement> media_element, NonnullRefPtr<Audio::Loader> loader)
29
0
    : PlatformObject(realm)
30
0
    , m_media_element(media_element)
31
0
    , m_audio_plugin(Platform::AudioCodecPlugin::create(move(loader)).release_value_but_fixme_should_propagate_errors())
32
0
{
33
0
    m_audio_plugin->on_playback_position_updated = [this](auto position) {
34
0
        if (auto const* paintable = m_media_element->paintable())
35
0
            paintable->set_needs_display();
36
37
0
        auto playback_position = static_cast<double>(position.to_milliseconds()) / 1000.0;
38
0
        m_media_element->set_current_playback_position(playback_position);
39
0
    };
40
41
0
    m_audio_plugin->on_decoder_error = [this](String error_message) {
42
0
        m_media_element->set_decoder_error(move(error_message));
43
0
    };
44
0
}
45
46
AudioTrack::~AudioTrack()
47
0
{
48
0
    auto id = m_id.to_number<int>();
49
0
    VERIFY(id.has_value());
50
51
0
    s_audio_track_id_allocator.deallocate(id.value());
52
0
}
53
54
void AudioTrack::initialize(JS::Realm& realm)
55
0
{
56
0
    Base::initialize(realm);
57
0
    WEB_SET_PROTOTYPE_FOR_INTERFACE(AudioTrack);
58
59
0
    auto id = s_audio_track_id_allocator.allocate();
60
0
    m_id = String::number(id);
61
0
}
62
63
void AudioTrack::play(Badge<HTMLAudioElement>)
64
0
{
65
0
    m_audio_plugin->resume_playback();
66
0
}
67
68
void AudioTrack::pause(Badge<HTMLAudioElement>)
69
0
{
70
0
    m_audio_plugin->pause_playback();
71
0
}
72
73
AK::Duration AudioTrack::duration()
74
0
{
75
0
    return m_audio_plugin->duration();
76
0
}
77
78
void AudioTrack::seek(double position, MediaSeekMode seek_mode)
79
0
{
80
    // FIXME: Implement seeking mode.
81
0
    (void)seek_mode;
82
83
0
    m_audio_plugin->seek(position);
84
0
}
85
86
void AudioTrack::update_volume()
87
0
{
88
0
    m_audio_plugin->set_volume(m_media_element->effective_media_volume());
89
0
}
90
91
void AudioTrack::visit_edges(Cell::Visitor& visitor)
92
0
{
93
0
    Base::visit_edges(visitor);
94
0
    visitor.visit(m_media_element);
95
0
    visitor.visit(m_audio_track_list);
96
0
}
97
98
// https://html.spec.whatwg.org/multipage/media.html#dom-audiotrack-enabled
99
void AudioTrack::set_enabled(bool enabled)
100
0
{
101
    // On setting, it must enable the track if the new value is true, and disable it otherwise. (If the track is no
102
    // longer in an AudioTrackList object, then the track being enabled or disabled has no effect beyond changing the
103
    // value of the attribute on the AudioTrack object.)
104
0
    if (m_enabled == enabled)
105
0
        return;
106
107
0
    if (m_audio_track_list) {
108
        // Whenever an audio track in an AudioTrackList that was disabled is enabled, and whenever one that was enabled
109
        // is disabled, the user agent must queue a media element task given the media element to fire an event named
110
        // change at the AudioTrackList object.
111
0
        m_media_element->queue_a_media_element_task([this]() {
112
0
            m_audio_track_list->dispatch_event(DOM::Event::create(realm(), HTML::EventNames::change));
113
0
        });
114
0
    }
115
116
0
    m_enabled = enabled;
117
0
}
118
119
}