mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-28 02:27:19 +02:00
This prevents PlaybackManager's seek while enabling an audio track from causing the AudioMixingSink to push audio blocks forward unnecessarily. Previously, the seek would cause the initial block or blocks to repeat from the perspective of AudioMixingSink, so it would think that it needs to shift the first block after the seek forward by a few samples. By moving this to the AudioDataProvider, we can clear the last sample index every time the decoder is flushed, ensuring that the block shifting always makes sense. By doing this in AudioMixingSink instead of the Decoder implementations, we avoid having to duplicate this shifting logic across multiple implementations. This also fixes an issue where multiple audio blocks occupying the same timestamp would be skipped while seeking, causing a significant break in audio.
101 lines
3.1 KiB
C++
101 lines
3.1 KiB
C++
/*
|
|
* Copyright (c) 2025, Gregory Bertilson <gregory@ladybird.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/HashMap.h>
|
|
#include <AK/NonnullRefPtr.h>
|
|
#include <AK/RefPtr.h>
|
|
#include <LibCore/EventLoop.h>
|
|
#include <LibMedia/Audio/Forward.h>
|
|
#include <LibMedia/Audio/SampleFormats.h>
|
|
#include <LibMedia/Export.h>
|
|
#include <LibMedia/Forward.h>
|
|
#include <LibMedia/Providers/MediaTimeProvider.h>
|
|
#include <LibMedia/Sinks/AudioSink.h>
|
|
#include <LibThreading/ConditionVariable.h>
|
|
#include <LibThreading/Mutex.h>
|
|
|
|
namespace Media {
|
|
|
|
class MEDIA_API AudioMixingSink final : public AudioSink {
|
|
class AudioMixingSinkWeakReference;
|
|
|
|
public:
|
|
static ErrorOr<NonnullRefPtr<AudioMixingSink>> try_create();
|
|
AudioMixingSink(AudioMixingSinkWeakReference&);
|
|
virtual ~AudioMixingSink() override;
|
|
|
|
virtual void set_provider(Track const&, RefPtr<AudioDataProvider> const&) override;
|
|
virtual RefPtr<AudioDataProvider> provider(Track const&) const override;
|
|
|
|
// This section implements the pure virtuals in MediaTimeProvider.
|
|
// AudioMixingSink cannot inherit from MediaTimeProvider, as AudioSink and MediaTimeProvider both inherit from
|
|
// AtomicRefCounted. In order to use AudioMixingSink as a MediaTimeProvider, wrap it with WrapperTimeProvider.
|
|
AK::Duration current_time() const;
|
|
void resume();
|
|
void pause();
|
|
void set_time(AK::Duration);
|
|
|
|
void set_volume(double);
|
|
|
|
private:
|
|
static constexpr size_t MAX_BLOCK_COUNT = 16;
|
|
|
|
class AudioMixingSinkWeakReference : public AtomicRefCounted<AudioMixingSinkWeakReference> {
|
|
public:
|
|
void emplace(AudioMixingSink& sink) { m_ptr = &sink; }
|
|
RefPtr<AudioMixingSink> take_strong() const
|
|
{
|
|
Threading::MutexLocker locker { m_mutex };
|
|
return m_ptr;
|
|
}
|
|
void revoke()
|
|
{
|
|
Threading::MutexLocker locker { m_mutex };
|
|
m_ptr = nullptr;
|
|
}
|
|
|
|
private:
|
|
mutable Threading::Mutex m_mutex;
|
|
AudioMixingSink* m_ptr { nullptr };
|
|
};
|
|
|
|
struct TrackMixingData {
|
|
TrackMixingData(NonnullRefPtr<AudioDataProvider> const& provider)
|
|
: provider(provider)
|
|
{
|
|
}
|
|
|
|
NonnullRefPtr<AudioDataProvider> provider;
|
|
AudioBlock current_block;
|
|
};
|
|
|
|
void deferred_create_playback_stream(Track const& track);
|
|
void create_playback_stream(u32 sample_rate, u32 channel_count);
|
|
ReadonlyBytes write_audio_data_to_playback_stream(Bytes buffer, Audio::PcmSampleFormat format, size_t sample_count);
|
|
|
|
Core::EventLoop& m_main_thread_event_loop;
|
|
NonnullRefPtr<AudioMixingSinkWeakReference> m_weak_self;
|
|
|
|
Threading::Mutex m_mutex;
|
|
Threading::ConditionVariable m_wait_condition { m_mutex };
|
|
RefPtr<Audio::PlaybackStream> m_playback_stream;
|
|
u32 m_playback_stream_sample_rate { 0 };
|
|
u32 m_playback_stream_channel_count { 0 };
|
|
bool m_playing { false };
|
|
double m_volume { 1 };
|
|
|
|
HashMap<Track, TrackMixingData> m_track_mixing_datas;
|
|
Atomic<i64, MemoryOrder::memory_order_relaxed> m_next_sample_to_write { 0 };
|
|
|
|
AK::Duration m_last_stream_time;
|
|
AK::Duration m_last_media_time;
|
|
Optional<AK::Duration> m_temporary_time;
|
|
};
|
|
|
|
}
|