diff options
Diffstat (limited to 'audio/out/internal.h')
-rw-r--r-- | audio/out/internal.h | 158 |
1 files changed, 79 insertions, 79 deletions
diff --git a/audio/out/internal.h b/audio/out/internal.h index bf769d7e1c..51429b9c06 100644 --- a/audio/out/internal.h +++ b/audio/out/internal.h @@ -18,10 +18,9 @@ #ifndef MP_AO_INTERNAL_H_ #define MP_AO_INTERNAL_H_ +#include <stdatomic.h> #include <stdbool.h> -#include <pthread.h> -#include "osdep/atomic.h" #include "audio/out/ao.h" /* global data used by ao.c and ao drivers */ @@ -37,8 +36,8 @@ struct ao { bool untimed; // don't assume realtime playback int device_buffer; // device buffer in samples (guessed by // common init code if not set by driver) - const struct ao_driver *api; // entrypoints to the wrapper (push.c/pull.c) const struct ao_driver *driver; + bool driver_initialized; void *priv; struct mpv_global *global; struct encode_lavc_context *encode_lavc_ctx; @@ -48,14 +47,6 @@ struct ao { int init_flags; // AO_INIT_* flags bool stream_silence; // if audio inactive, just play silence - // Set by the driver on init. This is typically the period size, and the - // smallest unit the driver will accept in one piece (although if - // AOPLAY_FINAL_CHUNK is set, the driver must accept everything). - // This value is in complete samples (i.e. 1 for stereo means 1 sample - // for both channels each). - // Used for push based API only. - int period_size; - // The device as selected by the user, usually using ao_device_desc.name // from an entry from the list returned by driver->list_devices. If the // default device should be used, this is set to NULL. @@ -68,19 +59,37 @@ struct ao { char *redirect; // Internal events (use ao_request_reload(), ao_hotplug_event()) - atomic_int events_; + atomic_uint events_; // Float gain multiplicator - mp_atomic_float gain; + _Atomic float gain; int buffer; double def_buffer; - void *api_priv; + struct buffer_state *buffer_state; }; -extern const struct ao_driver ao_api_push; -extern const struct ao_driver ao_api_pull; - +void init_buffer_pre(struct ao *ao); +bool init_buffer_post(struct ao *ao); + +struct mp_pcm_state { + // Note: free_samples+queued_samples <= ao->device_buffer; the sum may be + // less if the audio API can report partial periods played, while + // free_samples should be period-size aligned. If free_samples is not + // period-size aligned, the AO thread might get into a situation where + // it writes a very small number of samples in each iteration, leading + // to extremely inefficient behavior. + // Keep in mind that write() may write less than free_samples (or your + // period size alignment) anyway. + int free_samples; // number of free space in ring buffer + int queued_samples; // number of samples to play in ring buffer + double delay; // total latency in seconds (includes queued_samples) + bool playing; // set if underlying API is actually playing audio; + // the AO must unset it on underrun (accidental + // underrun and EOF are indistinguishable; the upper + // layers decide what it was) + // real pausing may assume playing=true +}; /* Note: * @@ -89,39 +98,31 @@ extern const struct ao_driver ao_api_pull; * b) pull callback based (the audio API calls a callback to get audio) * * The ao.c code can handle both. It basically implements two audio paths - * and provides a uniform API for them. If ao_driver->play is NULL, it assumes + * and provides a uniform API for them. If ao_driver->write is NULL, it assumes * that the driver uses a callback based audio API, otherwise push based. * * Requirements: - * a) ->play is called to queue audio. push.c creates a thread to regularly - * refill audio device buffers with ->play, but all driver functions are - * always called under an exclusive lock. - * Mandatory: + * a+b) Mandatory for both types: * init * uninit - * reset - * get_space - * play - * get_delay - * pause - * resume - * Optional: + * start + * Optional for both types: * control - * drain - * wait - * wakeup - * b) ->play must be NULL. ->resume must be provided, and should make the + * set_pause + * a) ->write is called to queue audio. push.c creates a thread to regularly + * refill audio device buffers with ->write, but all driver functions are + * always called under an exclusive lock. + * Mandatory: + * reset + * write + * get_state + * b) ->write must be NULL. ->start must be provided, and should make the * audio API start calling the audio callback. Your audio callback should * in turn call ao_read_data() to get audio data. Most functions are * optional and will be emulated if missing (e.g. pausing is emulated as - * silence). ->get_delay and ->get_space are never called. - * Mandatory: - * init - * uninit - * resume (starts the audio callback) + * silence). * Also, the following optional callbacks can be provided: - * reset (stops the audio callback, resume() restarts it) - * control + * reset (stops the audio callback, start() restarts it) */ struct ao_driver { // If true, use with encoding only. @@ -131,9 +132,12 @@ struct ao_driver { // Description shown with --ao=help. const char *description; // This requires waiting for a AO_EVENT_INITIAL_UNBLOCK event before the - // first play() call is done. Encode mode uses this, and push mode + // first write() call is done. Encode mode uses this, and push mode // respects it automatically (don't use with pull mode). bool initially_blocked; + // If true, write units of entire frames. The write() call is modified to + // use data==mp_aframe. Useful for encoding AO only. + bool write_frames; // Init the device using ao->format/ao->channels/ao->samplerate. If the // device doesn't accept these parameters, you can attempt to negotiate // fallback parameters, and set the ao format fields accordingly. @@ -141,38 +145,35 @@ struct ao_driver { // Optional. See ao_control() etc. in ao.c int (*control)(struct ao *ao, enum aocontrol cmd, void *arg); void (*uninit)(struct ao *ao); - // push based: see ao_reset() - // pull based: stop the audio callback - void (*reset)(struct ao*ao); - // push based: see ao_pause() - void (*pause)(struct ao *ao); - // push based: see ao_resume() + // Stop all audio playback, clear buffers, back to state after init(). + // Optional for pull AOs. + void (*reset)(struct ao *ao); + // pull based: set pause state. Only called after start() and before reset(). + // The return value is ignored. + // The pausing state is also cleared by reset(). + // push based: set pause state. Only called after start() and before reset(). + // returns success (this is intended for paused=true; if it + // returns false, playback continues, and the core emulates via + // reset(); unpausing always works) + // The pausing state is also cleared by reset(). + bool (*set_pause)(struct ao *ao, bool paused); // pull based: start the audio callback - void (*resume)(struct ao *ao); - // push based: see ao_play() - int (*get_space)(struct ao *ao); - // push based: see ao_play() - int (*play)(struct ao *ao, void **data, int samples, int flags); - // push based: see ao_get_delay() - double (*get_delay)(struct ao *ao); - // push based: block until all queued audio is played (optional) - void (*drain)(struct ao *ao); - // Optional. Return true if audio has stopped in any way. - bool (*get_eof)(struct ao *ao); - // Wait until the audio buffer needs to be refilled. The lock is the - // internal mutex usually protecting the internal AO state (and used to - // protect driver calls), and must be temporarily unlocked while waiting. - // ->wakeup will be called (with lock held) if the wait should be canceled. - // Returns 0 on success, -1 on error. - // Optional; if this is not provided, generic code using audio timing is - // used to estimate when the AO needs to be refilled. - // Warning: it's only called if the feed thread truly needs to know when - // the audio thread takes data again. Often, it will just copy - // the complete soft-buffer to the AO, and then wait for the - // decoder instead. Don't do necessary work in this callback. - int (*wait)(struct ao *ao, pthread_mutex_t *lock); - // In combination with wait(). Lock may or may not be held. - void (*wakeup)(struct ao *ao); + // push based: start playing queued data + // AO should call ao_wakeup() if a period boundary + // is crossed, or playback stops due to external reasons + // (including underruns or device removal) + // must set mp_pcm_state.playing; unset on error/underrun/end + void (*start)(struct ao *ao); + // push based: queue new data. This won't try to write more data than the + // reported free space (samples <= mp_pcm_state.free_samples). + // This must NOT start playback. start() does that, and write() may be + // called multiple times before start() is called. It may also happen that + // reset() is called to discard the buffer. start() without write() will + // immediately reported an underrun. + // Return false on failure. + bool (*write)(struct ao *ao, void **data, int samples); + // push based: return mandatory stream information + void (*get_state)(struct ao *ao, struct mp_pcm_state *state); // Return the list of devices currently available in the system. Use // ao_device_list_add() to add entries. The selected device will be set as @@ -200,12 +201,9 @@ struct ao_driver { // These functions can be called by AOs. -int ao_play_silence(struct ao *ao, int samples); -int ao_read_data(struct ao *ao, void **data, int samples, int64_t out_time_us); -struct pollfd; -int ao_wait_poll(struct ao *ao, struct pollfd *fds, int num_fds, - pthread_mutex_t *lock); -void ao_wakeup_poll(struct ao *ao); +int ao_read_data(struct ao *ao, void **data, int samples, int64_t out_time_ns); +MP_WARN_UNUSED_RESULT +int ao_read_data_nonblocking(struct ao *ao, void **data, int samples, int64_t out_time_ns); bool ao_chmap_sel_adjust(struct ao *ao, const struct mp_chmap_sel *s, struct mp_chmap *map); @@ -233,7 +231,9 @@ bool ao_can_convert_inplace(struct ao_convert_fmt *fmt); bool ao_need_conversion(struct ao_convert_fmt *fmt); void ao_convert_inplace(struct ao_convert_fmt *fmt, void **data, int num_samples); +void ao_wakeup(struct ao *ao); + int ao_read_data_converted(struct ao *ao, struct ao_convert_fmt *fmt, - void **data, int samples, int64_t out_time_us); + void **data, int samples, int64_t out_time_ns); #endif |