mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-28 10:37:17 +02:00
Instead of specifying the sample rate, channel count/map, etc. to the PlaybackStream, we'll now use the output device's sample specification whenever possible. If necessary, the stream will fall back to sane default. This hugely simplifies AudioMixingSink, since it no longer has to take care of reinitializing the stream with a new sample specification when it encounters a track with a higher sample rate or more channels. We wouldn't be likely to benefit from this anyway, since it turns out that at least Windows's virtual surround doesn't work through WASAPI at all, and WASAPI likely wouldn't support downmixing. This commit breaks playback of audio files that don't match the system default audio device's sample rate and channel count. The next commit introduces a converter into the pipeline to allow mixing of any sample specification.
62 lines
1.8 KiB
C++
62 lines
1.8 KiB
C++
/*
|
|
* Copyright (c) 2023-2025, Gregory Bertilson <gregory@ladybird.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "PlaybackStream.h"
|
|
#include "PulseAudioWrappers.h"
|
|
#include <AK/Queue.h>
|
|
#include <LibThreading/ConditionVariable.h>
|
|
#include <LibThreading/Mutex.h>
|
|
|
|
namespace Audio {
|
|
|
|
class PlaybackStreamPulseAudio final
|
|
: public PlaybackStream {
|
|
public:
|
|
static ErrorOr<NonnullRefPtr<PlaybackStream>> create(OutputState, u32 target_latency_ms, SampleSpecificationCallback&&, AudioDataRequestCallback&&);
|
|
|
|
virtual void set_underrun_callback(Function<void()>) override;
|
|
|
|
virtual NonnullRefPtr<Core::ThreadedPromise<AK::Duration>> resume() override;
|
|
virtual NonnullRefPtr<Core::ThreadedPromise<void>> drain_buffer_and_suspend() override;
|
|
virtual NonnullRefPtr<Core::ThreadedPromise<void>> discard_buffer_and_suspend() override;
|
|
|
|
virtual AK::Duration total_time_played() const override;
|
|
|
|
virtual NonnullRefPtr<Core::ThreadedPromise<void>> set_volume(double) override;
|
|
|
|
private:
|
|
// This struct is kept alive until the control thread exits to prevent a use-after-free without blocking on
|
|
// the UI thread.
|
|
class InternalState : public AtomicRefCounted<InternalState> {
|
|
public:
|
|
void set_stream(NonnullRefPtr<PulseAudioStream>&&);
|
|
RefPtr<PulseAudioStream> stream();
|
|
|
|
void enqueue(Function<void()>&&);
|
|
void thread_loop();
|
|
ErrorOr<void> check_is_running();
|
|
void exit();
|
|
|
|
private:
|
|
RefPtr<PulseAudioStream> m_stream { nullptr };
|
|
|
|
Queue<Function<void()>> m_tasks;
|
|
Threading::Mutex m_mutex;
|
|
Threading::ConditionVariable m_wake_condition { m_mutex };
|
|
|
|
Atomic<bool> m_exit { false };
|
|
};
|
|
|
|
PlaybackStreamPulseAudio(NonnullRefPtr<InternalState>);
|
|
~PlaybackStreamPulseAudio();
|
|
|
|
RefPtr<InternalState> m_state;
|
|
};
|
|
|
|
}
|