LibWeb+LibMedia: Wire up setting the pipeline's playback rate

However, the playback rate is still limited to 1.0 at the element,
because audio stretching is not yet implemented.
This commit is contained in:
Zaggy1024 2026-06-03 06:37:23 -05:00 committed by Gregory Bertilson
parent 47207b69e6
commit 7ddbc2d7dd
11 changed files with 75 additions and 5 deletions

View file

@ -15,8 +15,12 @@ GenericTimeProvider::~GenericTimeProvider() = default;
AK::Duration GenericTimeProvider::current_time() const
{
auto time = m_media_time;
if (m_monotonic_time_on_resume.has_value())
time += MonotonicTime::now() - m_monotonic_time_on_resume.value();
if (m_monotonic_time_on_resume.has_value()) {
auto elapsed = MonotonicTime::now() - m_monotonic_time_on_resume.value();
if (m_playback_rate != 1.0f)
elapsed = AK::Duration::from_seconds_f64(elapsed.to_seconds_f64() * m_playback_rate);
time += elapsed;
}
return time;
}
@ -41,4 +45,16 @@ void GenericTimeProvider::seek(AK::Duration time)
m_media_time = time;
}
void GenericTimeProvider::set_playback_rate(float rate)
{
VERIFY(rate >= 0);
if (m_playback_rate == rate)
return;
if (m_monotonic_time_on_resume.has_value()) {
m_media_time = current_time();
m_monotonic_time_on_resume.emplace(MonotonicTime::now());
}
m_playback_rate = rate;
}
}

View file

@ -19,10 +19,12 @@ public:
virtual void resume() override;
virtual void pause() override;
virtual void seek(AK::Duration) override;
virtual void set_playback_rate(float) override;
private:
Optional<MonotonicTime> m_monotonic_time_on_resume;
AK::Duration m_media_time;
float m_playback_rate { 1.0f };
};
}

View file

@ -19,6 +19,7 @@ public:
virtual void resume() = 0;
virtual void pause() = 0;
virtual void seek(AK::Duration) = 0;
virtual void set_playback_rate(float) = 0;
};
}

View file

@ -301,6 +301,7 @@ void PlaybackManager::set_time_provider(NonnullRefPtr<MediaTimeProvider> const&
continue;
track_data.display->set_time_provider(provider);
}
provider->set_playback_rate(m_playback_rate);
if (is_playing())
provider->resume();
}
@ -432,4 +433,10 @@ void PlaybackManager::set_volume(double volume)
m_audio_sink->set_volume(volume);
}
void PlaybackManager::set_playback_rate(float rate)
{
m_playback_rate = rate;
m_time_provider->set_playback_rate(rate);
}
}

View file

@ -89,6 +89,7 @@ public:
TimeRanges buffered_time_ranges() const;
void set_volume(double);
void set_playback_rate(float);
Function<void()> on_metadata_parsed;
Function<void(DecoderError&&)> on_unsupported_format_error;
@ -162,6 +163,7 @@ private:
NonnullRefPtr<WeakPlaybackManagerLink> m_weak_link;
NonnullRefPtr<MediaTimeProvider> m_time_provider;
float m_playback_rate { 1.0f };
bool m_audio_output_disabled { false };

View file

@ -49,6 +49,7 @@ ErrorOr<void> AudioMixer::connect_input(NonnullRefPtr<AudioProducer> const& inpu
disconnect_input_while_locked(input);
return result.release_error();
}
input->set_playback_rate(m_playback_rate);
input->seek(mix_head_timestamp());
if (m_started)
input->start();
@ -118,6 +119,16 @@ Audio::SampleSpecification AudioMixer::sample_specification() const
return m_sample_specification;
}
void AudioMixer::set_playback_rate(float rate)
{
Sync::MutexLocker locker { m_mutex };
if (m_playback_rate == rate)
return;
for (auto& [input, input_data] : m_inputs)
input->set_playback_rate(rate);
m_playback_rate = rate;
}
AK::Duration AudioMixer::mix_head_timestamp() const
{
return AK::Duration::from_time_units(m_next_frame_to_write, 1, m_sample_specification.sample_rate());

View file

@ -33,6 +33,8 @@ public:
virtual void seek(AK::Duration timestamp) override;
virtual void set_playback_rate(float) override;
virtual ErrorOr<void> set_output_sample_specification(Audio::SampleSpecification) override;
Audio::SampleSpecification sample_specification() const;
@ -60,6 +62,7 @@ private:
Audio::SampleSpecification m_sample_specification;
mutable HashMap<NonnullRefPtr<AudioProducer>, InputMixingData> m_inputs;
i64 m_next_frame_to_write { 0 };
float m_playback_rate { 1.0f };
bool m_started { false };
bool m_moved_position_pending { false };
mutable bool m_downstream_needs_wake { true };

View file

@ -26,6 +26,11 @@ public:
virtual void set_wake_handler(PipelineWakeHandler) = 0;
virtual void seek(AK::Duration timestamp) = 0;
virtual void set_playback_rate(float rate)
{
VERIFY(rate == 1.0f);
}
};
}

View file

@ -49,6 +49,7 @@ public:
size_t m_block_count { 0 };
i64 m_next_frame_to_play { 0 };
AudioBlockTimingRing m_block_timings;
float m_playback_rate { 1.0f };
PipelineStateChangeHandler m_on_state_changed;
PipelineStatus m_last_pull_status { PipelineStatus::Pending };
@ -196,6 +197,7 @@ ErrorOr<void> AudioPlaybackSink::connect_input(NonnullRefPtr<AudioProducer> cons
disconnect_input_while_locked(input);
return result.release_error();
}
input->set_playback_rate(m_output_thread_data->m_playback_rate);
input->seek(current_time());
input->start();
}
@ -467,4 +469,17 @@ void AudioPlaybackSink::set_volume(double volume)
}
}
void AudioPlaybackSink::set_playback_rate(float rate)
{
VERIFY(rate >= 0);
RefPtr<AudioProducer> input;
{
Sync::MutexLocker locker { m_output_thread_data->m_output_mutex };
input = m_output_thread_data->m_input;
m_output_thread_data->m_playback_rate = rate;
}
if (input != nullptr)
input->set_playback_rate(rate);
}
}

View file

@ -40,6 +40,8 @@ public:
virtual void pause() override;
virtual void seek(AK::Duration) override;
virtual void set_playback_rate(float) override;
void set_volume(double);
Function<void(Error&&)> on_audio_output_error;

View file

@ -1781,6 +1781,8 @@ void HTMLMediaElement::set_up_playback_manager_for_remote()
m_playback_manager = Media::PlaybackManager::create();
m_playback_manager->set_audio_output_disabled(document().page().client().is_headless());
m_playback_manager->set_playback_rate(static_cast<float>(m_playback_rate));
m_has_enabled_preferred_audio_track = false;
m_has_selected_preferred_video_track = false;
@ -1856,6 +1858,8 @@ void HTMLMediaElement::set_up_playback_manager_for_local()
m_playback_manager = Media::PlaybackManager::create();
m_playback_manager->set_audio_output_disabled(document().page().client().is_headless());
m_playback_manager->set_playback_rate(static_cast<float>(m_playback_rate));
m_has_enabled_preferred_audio_track = false;
m_has_selected_preferred_video_track = false;
@ -2602,9 +2606,11 @@ WebIDL::ExceptionOr<void> HTMLMediaElement::set_playback_rate(double new_value)
// 2. Set playbackRate to the new value, and if the element is potentially playing, change the playback speed.
m_playback_rate = new_value;
if (potentially_playing()) {
// FIXME: Do this once playback speeds other than 1 are supported.
}
// AD-HOC: Set the playback rate even when not potentially playing. The spec mandates that the media time advances
// by playbackRate units of media time per unit time on the clock. There's no reason this shouldn't be set
// always.
if (m_playback_manager)
m_playback_manager->set_playback_rate(static_cast<float>(new_value));
return {};
}