/* * Copyright (c) 2025, Gregory Bertilson * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Media { // Retrieves coded data from a demuxer and decodes it asynchronously into audio samples to push to an AudioSink. class MEDIA_API AudioDataProvider : public AtomicRefCounted { class ThreadData; public: static constexpr size_t QUEUE_CAPACITY = 16; using AudioQueue = Queue; using ErrorHandler = Function; using SeekCompletionHandler = Function; static DecoderErrorOr> try_create(NonnullRefPtr const& demuxer, Track const& track); AudioDataProvider(NonnullRefPtr const&); ~AudioDataProvider(); void set_error_handler(ErrorHandler&&); AudioBlock retrieve_block(); void seek(AK::Duration timestamp, SeekCompletionHandler&& = nullptr); private: class ThreadData final : public AtomicRefCounted { public: ThreadData(NonnullRefPtr const&, Track const&, NonnullOwnPtr&&); ~ThreadData(); void set_error_handler(ErrorHandler&&); bool should_thread_exit() const; void flush_decoder(); DecoderErrorOr retrieve_next_block(AudioBlock&); bool handle_seek(); template void process_seek_on_main_thread(u32 seek_id, T&&); void resolve_seek(u32 seek_id); void push_data_and_decode_a_block(); void exit(); void set_stopped(bool); bool is_stopped() const; void seek(AK::Duration timestamp, SeekCompletionHandler&&); [[nodiscard]] Threading::MutexLocker take_lock() { return Threading::MutexLocker(m_mutex); } void wake() { m_wait_condition.broadcast(); } AudioDecoder const& decoder() const { return *m_decoder; } AudioQueue& queue() { return m_queue; } private: Core::EventLoop& m_main_thread_event_loop; Threading::Mutex m_mutex; Threading::ConditionVariable m_wait_condition { m_mutex }; Atomic m_exit { false }; NonnullRefPtr m_demuxer; Track m_track; NonnullOwnPtr m_decoder; i64 m_last_sample { NumericLimits::min() }; size_t m_queue_max_size { 8 }; AudioQueue m_queue; ErrorHandler m_error_handler; bool m_is_in_error_state { false }; u32 m_last_processed_seek_id { 0 }; Atomic m_seek_id { 0 }; SeekCompletionHandler m_seek_completion_handler; AK::Duration m_seek_timestamp; }; NonnullRefPtr m_thread_data; }; }