// Native audio runtime // Part of the AC6 Recompilation native foundation #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include namespace rex::stream { class ByteStream; } namespace rex::system { class KernelState; } namespace rex::audio { struct AudioClientSnapshot { bool in_use{false}; uint32_t callback{0}; uint32_t callback_arg{0}; uint32_t render_driver_tic{0}; AudioDriverTelemetry telemetry{}; }; struct AudioTelemetrySnapshot { uint32_t active_clients{0}; uint32_t queued_frames{0}; uint32_t peak_queued_frames{0}; uint32_t dropped_frames{0}; uint32_t underruns{0}; uint32_t silence_injections{0}; uint64_t trace_event_count{0}; std::string backend_name; std::array clients{}; }; struct AudioClientTimingSnapshot { uint64_t consumed_samples{0}; uint64_t consumed_frames{0}; uint64_t submitted_tic{0}; uint64_t startup_cap_tic{0}; uint64_t synthetic_startup_tic{0}; uint64_t callback_floor_tic{0}; uint64_t host_elapsed_tic{0}; uint32_t startup_inflight_frames{0}; uint32_t render_driver_tic{0}; uint32_t callback_dispatch_count{0}; uint32_t callback_throttle_count{0}; uint32_t callback_empty_count{0}; uint32_t last_callback_produced_frames{0}; uint32_t last_callback_duration_us{0}; }; class AudioRuntime { public: AudioRuntime(memory::Memory* memory, runtime::FunctionDispatcher* function_dispatcher); ~AudioRuntime(); X_STATUS Setup(system::KernelState* kernel_state); void Shutdown(); X_STATUS RegisterClient(uint32_t callback, uint32_t callback_arg, size_t* out_index); bool UnregisterClient(size_t index); bool SubmitFrame(size_t index, uint32_t samples_ptr); bool SubmitSilenceFrame(size_t index); bool ConsumeNextFrameForClient(size_t index, AudioFrame* out_frame); void ReportSamplesConsumedForClient(size_t index, uint32_t sample_count); bool ShouldRequestCallbackForClient(size_t index) const; AudioDriverTelemetry GetClientTelemetry(size_t index) const; uint32_t GetClientRenderDriverTic(size_t index) const; AudioClientTimingSnapshot GetClientTimingSnapshot(size_t index) const; AudioTelemetrySnapshot GetTelemetrySnapshot() const; bool Save(stream::ByteStream* stream); bool Restore(stream::ByteStream* stream); void Pause(); void Resume(); bool is_paused() const; size_t ConsumeQueuedFramesForClient(size_t index, size_t max_frames); size_t ConsumeAllAvailableFrames(); AudioTraceBuffer& trace_buffer() { return trace_buffer_; } const AudioTraceBuffer& trace_buffer() const { return trace_buffer_; } std::string backend_name() const; /// Wake the audio worker thread to re-evaluate callback demand. /// Called by the host backend when it consumes frames or detects underruns. void WakeWorker(); private: void WorkerThreadMain(); uint64_t NextTickLocked(); mutable std::mutex mutex_; memory::Memory* memory_{nullptr}; runtime::FunctionDispatcher* function_dispatcher_{nullptr}; system::KernelState* kernel_state_{nullptr}; std::array clients_{}; AudioTraceBuffer trace_buffer_; bool paused_{false}; std::atomic worker_running_{false}; std::unique_ptr worker_thread_; system::object_ref worker_thread_context_; std::unique_ptr worker_wake_event_; std::unique_ptr shutdown_event_; uint64_t tick_counter_{0}; uint32_t peak_queued_frames_{0}; uint64_t worker_iteration_count_{0}; std::string backend_name_{"none"}; }; } // namespace rex::audio