#pragma once #include #include #include extern "C" { #include } namespace playback { // One decoding worker produces output. The native audio callback is the consumer. // Audio is interleaved stereo float at 48 kHz; write() never blocks. class Output { public: Output(); ~Output(); Output(const Output &) = delete; Output &operator=(const Output &) = delete; bool configure_audio(std::string &error); bool start(std::string &error); void pause(); // Atomic target gain; callback slews to it within 240 frames (5 ms). void set_volume(float normalized0to1) noexcept; float volume() const noexcept; // Called with audio stopped. Clears audio and video from the old timeline. void reset(); std::size_t write(const float *samples, std::size_t frames, double pts); std::size_t queued() const; // Latency-aware presented position; NaN until an audio callback has run. double clock() const; // Retains the frame's buffers; decoder may reuse its AVFrame after return. void present(const AVFrame *frame); // Returns a retained NSView. The view remains safe after Output is destroyed. void *make_video_view(); private: struct Impl; std::unique_ptr impl; }; }