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:
parent
47207b69e6
commit
7ddbc2d7dd
11 changed files with 75 additions and 5 deletions
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue