Files
ladybird/Libraries/LibWeb/MediaCapture/MediaStream.cpp
Shannon Booth 5adfd1c43a LibWeb/Bindings: Generate struct definitions from IDL dictionaries
Previously we were inconsistent by generating code for enum definitions
but not generating code for dictionaries. With future changes to the
IDL generator to expose helpers to convert to and from IDL values
this produced circular depdendencies. To solve this problem, also
generate the dictionary definitions in bindings headers.
2026-05-09 10:49:49 +02:00

198 lines
6.9 KiB
C++

/*
* Copyright (c) 2026, The Ladybird developers
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Bindings/MediaStream.h>
#include <LibWeb/Bindings/MediaStreamTrack.h>
#include <LibWeb/Bindings/MediaStreamTrackEvent.h>
#include <LibWeb/Crypto/Crypto.h>
#include <LibWeb/HTML/EventNames.h>
#include <LibWeb/MediaCapture/MediaStream.h>
#include <LibWeb/MediaCapture/MediaStreamTrackEvent.h>
namespace Web::MediaCapture {
GC_DEFINE_ALLOCATOR(MediaStream);
MediaStream::MediaStream(JS::Realm& realm)
: DOM::EventTarget(realm)
{
}
GC::Ref<MediaStream> MediaStream::create(JS::Realm& realm)
{
auto stream = realm.create<MediaStream>(realm);
// https://w3c.github.io/mediacapture-main/#dom-mediastream-id
stream->m_id = Crypto::generate_random_uuid();
return stream;
}
// https://w3c.github.io/mediacapture-main/#mediastream
GC::Ref<MediaStream> MediaStream::construct_impl(JS::Realm& realm, Vector<GC::Root<MediaStreamTrack>> const& tracks)
{
// 1. Let stream be a newly constructed MediaStream object.
// 2. Initialize stream.id attribute to a newly generated value.
auto stream = create(realm);
// 3. If the constructor's argument is present, run the following steps:
// 3.1. Construct a set of tracks tracks based on the type of argument.
// 3.2. For each MediaStreamTrack, track, in tracks:
for (auto const& track : tracks) {
// 3.2.1. If track is already in stream's track set, skip track.
// 3.2.2. Otherwise, add track to stream's track set.
stream->add_track(*track);
}
// 4. Return stream.
return stream;
}
void MediaStream::initialize(JS::Realm& realm)
{
WEB_SET_PROTOTYPE_FOR_INTERFACE(MediaStream);
Base::initialize(realm);
}
void MediaStream::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
for (auto& track : m_tracks)
visitor.visit(track);
}
// https://w3c.github.io/mediacapture-main/#dom-mediastream-getaudiotracks
Vector<GC::Ref<MediaStreamTrack>> MediaStream::get_audio_tracks() const
{
// The getAudioTracks method MUST return a sequence that represents a snapshot of all the MediaStreamTrack objects in this stream's track set whose [[Kind]] is equal to "audio".
Vector<GC::Ref<MediaStreamTrack>> result;
for (auto const& track : m_tracks) {
if (track->is_audio())
result.append(track);
}
return result;
}
// https://w3c.github.io/mediacapture-main/#dom-mediastream-getvideotracks
Vector<GC::Ref<MediaStreamTrack>> MediaStream::get_video_tracks() const
{
// The getVideoTracks method MUST return a sequence that represents a snapshot of all the MediaStreamTrack objects in this stream's track set whose [[Kind]] is equal to "video".
Vector<GC::Ref<MediaStreamTrack>> result;
for (auto const& track : m_tracks) {
if (track->is_video())
result.append(track);
}
return result;
}
// https://w3c.github.io/mediacapture-main/#dom-mediastream-gettracks
Vector<GC::Ref<MediaStreamTrack>> MediaStream::get_tracks() const
{
// The getTracks method MUST return a sequence that represents a snapshot of all the MediaStreamTrack objects in this stream's track set, regardless of [[Kind]].
return m_tracks;
}
// https://w3c.github.io/mediacapture-main/#dom-mediastream-gettrackbyid
GC::Ptr<MediaStreamTrack> MediaStream::get_track_by_id(String const& track_id) const
{
// The getTrackById method MUST return either a MediaStreamTrack object from this stream's track set whose [[Id]] is equal to trackId, or null.
for (auto const& track : m_tracks) {
if (track->id() == track_id)
return track;
}
return nullptr;
}
// https://w3c.github.io/mediacapture-main/#dom-mediastream-addtrack
void MediaStream::add_track(GC::Ref<MediaStreamTrack> track)
{
// 1. Let track be the methods argument and stream the MediaStream object on which the method was called.
for (auto const& existing_track : m_tracks) {
// 2. If track is already in stream's track set, then abort these steps.
if (existing_track.ptr() == track.ptr())
return;
}
// 3. Add track to stream's track set.
m_tracks.append(track);
// 4. Fire a track event named addtrack with track at stream.
Bindings::MediaStreamTrackEventInit event_init {};
event_init.track = track;
auto event = MediaStreamTrackEvent::create(realm(), HTML::EventNames::addtrack, event_init);
dispatch_event(event);
}
// https://w3c.github.io/mediacapture-main/#dom-mediastream-removetrack
void MediaStream::remove_track(GC::Ref<MediaStreamTrack> track)
{
// 1. Let track be the methods argument and stream the MediaStream object on which the method was called.
// 2. If track is not in stream's track set, then abort these steps.
// 3. Remove track from stream's track set.
auto removed = m_tracks.remove_first_matching([&](auto const& existing_track) {
return existing_track.ptr() == track.ptr();
});
if (!removed)
return;
// 4. Fire a track event named removetrack with track at stream.
Bindings::MediaStreamTrackEventInit event_init;
event_init.track = track;
auto event = MediaStreamTrackEvent::create(realm(), HTML::EventNames::removetrack, event_init);
dispatch_event(event);
}
// https://w3c.github.io/mediacapture-main/#dom-mediastream-clone
GC::Ref<MediaStream> MediaStream::clone() const
{
// 1. Let streamClone be a newly constructed MediaStream object.
auto stream_clone = create(realm());
// 3. Clone each track in this MediaStream object and add the result to streamClone's track set.
for (auto const& track : m_tracks)
stream_clone->add_track(track->clone());
// 4. Return streamClone.
return stream_clone;
}
// https://w3c.github.io/mediacapture-main/#dom-mediastream-active
bool MediaStream::active() const
{
// The active attribute MUST return true if this MediaStream is active and false otherwise.
for (auto const& track : m_tracks) {
if (track->ready_state() != Bindings::MediaStreamTrackState::Ended)
return true;
}
return false;
}
// https://w3c.github.io/mediacapture-main/#dom-mediastream-onaddtrack
WebIDL::CallbackType* MediaStream::onaddtrack()
{
return event_handler_attribute(HTML::EventNames::addtrack);
}
void MediaStream::set_onaddtrack(WebIDL::CallbackType* event_handler)
{
// The event type of this event handler is addtrack.
set_event_handler_attribute(HTML::EventNames::addtrack, event_handler);
}
// https://w3c.github.io/mediacapture-main/#dom-mediastream-onremovetrack
WebIDL::CallbackType* MediaStream::onremovetrack()
{
return event_handler_attribute(HTML::EventNames::removetrack);
}
void MediaStream::set_onremovetrack(WebIDL::CallbackType* event_handler)
{
// The event type of this event handler is removetrack.
set_event_handler_attribute(HTML::EventNames::removetrack, event_handler);
}
}