mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 11:18:11 +00:00
LibWeb: Implement the HTMLMediaElement volume and muted IDL attributes
This commit is contained in:
parent
d3b8d88598
commit
b9e4dc2cb7
7 changed files with 101 additions and 0 deletions
|
@ -100,6 +100,11 @@ void AudioTrack::seek(double position, MediaSeekMode seek_mode)
|
||||||
m_loader->seek(position).release_value_but_fixme_should_propagate_errors();
|
m_loader->seek(position).release_value_but_fixme_should_propagate_errors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioTrack::update_volume()
|
||||||
|
{
|
||||||
|
m_audio_plugin->set_volume(m_media_element->effective_media_volume());
|
||||||
|
}
|
||||||
|
|
||||||
void AudioTrack::visit_edges(Cell::Visitor& visitor)
|
void AudioTrack::visit_edges(Cell::Visitor& visitor)
|
||||||
{
|
{
|
||||||
Base::visit_edges(visitor);
|
Base::visit_edges(visitor);
|
||||||
|
|
|
@ -28,6 +28,8 @@ public:
|
||||||
Duration duration() const;
|
Duration duration() const;
|
||||||
void seek(double, MediaSeekMode);
|
void seek(double, MediaSeekMode);
|
||||||
|
|
||||||
|
void update_volume();
|
||||||
|
|
||||||
String const& id() const { return m_id; }
|
String const& id() const { return m_id; }
|
||||||
String const& kind() const { return m_kind; }
|
String const& kind() const { return m_kind; }
|
||||||
String const& label() const { return m_label; }
|
String const& label() const { return m_label; }
|
||||||
|
|
|
@ -63,4 +63,11 @@ void HTMLAudioElement::on_seek(double position, MediaSeekMode seek_mode)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HTMLAudioElement::on_volume_change()
|
||||||
|
{
|
||||||
|
audio_tracks()->for_each_enabled_track([&](auto& audio_track) {
|
||||||
|
audio_track.update_volume();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ private:
|
||||||
virtual void on_playing() override;
|
virtual void on_playing() override;
|
||||||
virtual void on_paused() override;
|
virtual void on_paused() override;
|
||||||
virtual void on_seek(double, MediaSeekMode) override;
|
virtual void on_seek(double, MediaSeekMode) override;
|
||||||
|
virtual void on_volume_change() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,8 @@ void HTMLMediaElement::parse_attribute(DeprecatedFlyString const& name, Deprecat
|
||||||
load_element().release_value_but_fixme_should_propagate_errors();
|
load_element().release_value_but_fixme_should_propagate_errors();
|
||||||
else if (name == HTML::AttributeNames::crossorigin)
|
else if (name == HTML::AttributeNames::crossorigin)
|
||||||
m_crossorigin = cors_setting_attribute_from_keyword(String::from_deprecated_string(value).release_value_but_fixme_should_propagate_errors());
|
m_crossorigin = cors_setting_attribute_from_keyword(String::from_deprecated_string(value).release_value_but_fixme_should_propagate_errors());
|
||||||
|
else if (name == HTML::AttributeNames::muted)
|
||||||
|
set_muted(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTMLMediaElement::did_remove_attribute(DeprecatedFlyString const& name)
|
void HTMLMediaElement::did_remove_attribute(DeprecatedFlyString const& name)
|
||||||
|
@ -344,6 +346,69 @@ WebIDL::ExceptionOr<void> HTMLMediaElement::pause()
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/media.html#dom-media-volume
|
||||||
|
WebIDL::ExceptionOr<void> HTMLMediaElement::set_volume(double volume)
|
||||||
|
{
|
||||||
|
if (m_volume == volume)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
// On setting, if the new value is in the range 0.0 to 1.0 inclusive, the media element's playback volume must be
|
||||||
|
// set to the new value. If the new value is outside the range 0.0 to 1.0 inclusive, then, on setting, an
|
||||||
|
// "IndexSizeError" DOMException must be thrown instead.
|
||||||
|
if (volume < 0.0 || volume > 1.0)
|
||||||
|
return WebIDL::IndexSizeError::create(realm(), "Volume must be in the range 0.0 to 1.0, inclusive"sv);
|
||||||
|
|
||||||
|
m_volume = volume;
|
||||||
|
volume_or_muted_attribute_changed();
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/media.html#dom-media-muted
|
||||||
|
void HTMLMediaElement::set_muted(bool muted)
|
||||||
|
{
|
||||||
|
if (m_muted == muted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_muted = muted;
|
||||||
|
volume_or_muted_attribute_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/media.html#user-interface:dom-media-volume-3
|
||||||
|
void HTMLMediaElement::volume_or_muted_attribute_changed()
|
||||||
|
{
|
||||||
|
// Whenever either of the values that would be returned by the volume and muted IDL attributes change, the user
|
||||||
|
// agent must queue a media element task given the media element to fire an event named volumechange at the media
|
||||||
|
// element.
|
||||||
|
queue_a_media_element_task([this] {
|
||||||
|
dispatch_event(DOM::Event::create(realm(), HTML::EventNames::volumechange).release_value_but_fixme_should_propagate_errors());
|
||||||
|
});
|
||||||
|
|
||||||
|
// FIXME: Then, if the media element is not allowed to play, the user agent must run the internal pause steps for the media element.
|
||||||
|
|
||||||
|
on_volume_change();
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/media.html#effective-media-volume
|
||||||
|
double HTMLMediaElement::effective_media_volume() const
|
||||||
|
{
|
||||||
|
// FIXME 1. If the user has indicated that the user agent is to override the volume of the element, then return the
|
||||||
|
// volume desired by the user.
|
||||||
|
|
||||||
|
// 2. If the element's audio output is muted, then return zero.
|
||||||
|
if (m_muted)
|
||||||
|
return 0.0;
|
||||||
|
|
||||||
|
// 3. Let volume be the playback volume of the audio portions of the media element, in range 0.0 (silent) to
|
||||||
|
// 1.0 (loudest).
|
||||||
|
auto volume = clamp(m_volume, 0.0, 1.0);
|
||||||
|
|
||||||
|
// 4. Return volume, interpreted relative to the range 0.0 to 1.0, with 0.0 being silent, and 1.0 being the loudest
|
||||||
|
// setting, values in between increasing in loudness. The range need not be linear. The loudest setting may be
|
||||||
|
// lower than the system's loudest possible setting; for example the user could have set a maximum volume.
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/media.html#media-element-load-algorithm
|
// https://html.spec.whatwg.org/multipage/media.html#media-element-load-algorithm
|
||||||
WebIDL::ExceptionOr<void> HTMLMediaElement::load_element()
|
WebIDL::ExceptionOr<void> HTMLMediaElement::load_element()
|
||||||
{
|
{
|
||||||
|
|
|
@ -85,6 +85,14 @@ public:
|
||||||
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> play();
|
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> play();
|
||||||
WebIDL::ExceptionOr<void> pause();
|
WebIDL::ExceptionOr<void> pause();
|
||||||
|
|
||||||
|
double volume() const { return m_volume; }
|
||||||
|
WebIDL::ExceptionOr<void> set_volume(double);
|
||||||
|
|
||||||
|
bool muted() const { return m_muted; }
|
||||||
|
void set_muted(bool);
|
||||||
|
|
||||||
|
double effective_media_volume() const;
|
||||||
|
|
||||||
JS::NonnullGCPtr<AudioTrackList> audio_tracks() const { return *m_audio_tracks; }
|
JS::NonnullGCPtr<AudioTrackList> audio_tracks() const { return *m_audio_tracks; }
|
||||||
JS::NonnullGCPtr<VideoTrackList> video_tracks() const { return *m_video_tracks; }
|
JS::NonnullGCPtr<VideoTrackList> video_tracks() const { return *m_video_tracks; }
|
||||||
|
|
||||||
|
@ -118,6 +126,8 @@ protected:
|
||||||
// subclasses must invoke set_current_playback_position() to unblock the user agent.
|
// subclasses must invoke set_current_playback_position() to unblock the user agent.
|
||||||
virtual void on_seek(double, MediaSeekMode) { m_seek_in_progress = false; }
|
virtual void on_seek(double, MediaSeekMode) { m_seek_in_progress = false; }
|
||||||
|
|
||||||
|
virtual void on_volume_change() { }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend SourceElementSelector;
|
friend SourceElementSelector;
|
||||||
|
|
||||||
|
@ -142,6 +152,8 @@ private:
|
||||||
void set_paused(bool);
|
void set_paused(bool);
|
||||||
void set_duration(double);
|
void set_duration(double);
|
||||||
|
|
||||||
|
void volume_or_muted_attribute_changed();
|
||||||
|
|
||||||
bool blocked() const;
|
bool blocked() const;
|
||||||
bool is_eligible_for_autoplay() const;
|
bool is_eligible_for_autoplay() const;
|
||||||
bool has_ended_playback() const;
|
bool has_ended_playback() const;
|
||||||
|
@ -212,6 +224,12 @@ private:
|
||||||
// https://html.spec.whatwg.org/multipage/media.html#dom-media-paused
|
// https://html.spec.whatwg.org/multipage/media.html#dom-media-paused
|
||||||
bool m_paused { true };
|
bool m_paused { true };
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/media.html#dom-media-volume
|
||||||
|
double m_volume { 1.0 };
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/media.html#dom-media-muted
|
||||||
|
bool m_muted { false };
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/media.html#dom-media-audiotracks
|
// https://html.spec.whatwg.org/multipage/media.html#dom-media-audiotracks
|
||||||
JS::GCPtr<AudioTrackList> m_audio_tracks;
|
JS::GCPtr<AudioTrackList> m_audio_tracks;
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,9 @@ interface HTMLMediaElement : HTMLElement {
|
||||||
|
|
||||||
// controls
|
// controls
|
||||||
[Reflect, CEReactions] attribute boolean controls;
|
[Reflect, CEReactions] attribute boolean controls;
|
||||||
|
attribute double volume;
|
||||||
|
attribute boolean muted;
|
||||||
|
[Reflect=muted, CEReactions] attribute boolean defaultMuted;
|
||||||
|
|
||||||
// tracks
|
// tracks
|
||||||
[SameObject] readonly attribute AudioTrackList audioTracks;
|
[SameObject] readonly attribute AudioTrackList audioTracks;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue