summaryrefslogtreecommitdiffstats
path: root/audio/out/internal.h
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2020-05-31 15:00:35 +0200
committerwm4 <wm4@nowhere>2020-06-01 01:08:16 +0200
commitd27ad9654218463694093697e3d09f8983b4ccf3 (patch)
tree54d889bbed1b32b2a702fee6825c66ff6fb60c33 /audio/out/internal.h
parentd448dd5bf26408ccced1bd6df8f9eaf62a370c8e (diff)
downloadmpv-d27ad9654218463694093697e3d09f8983b4ccf3.tar.bz2
mpv-d27ad9654218463694093697e3d09f8983b4ccf3.tar.xz
audio: redo internal AO API
This affects "pull" AOs only: ao_alsa, ao_pulse, ao_openal, ao_pcm, ao_lavc. There are changes to the other AOs too, but that's only about renaming ao_driver.resume to ao_driver.start. ao_openal is broken because I didn't manage to fix it, so it exits with an error message. If you want it, why don't _you_ put effort into it? I see no reason to waste my own precious lifetime over this (I realize the irony). ao_alsa loses the poll() mechanism, but it was mostly broken and didn't really do what it was supposed to. There doesn't seem to be anything in the ALSA API to watch the playback status without polling (unless you want to use raw UNIX signals). No idea if ao_pulse is correct, or whether it's subtly broken now. There is no documentation, so I can't tell what is correct, without reverse engineering the whole project. I recommend using ALSA. This was supposed to be just a simple fix, but somehow it expanded scope like a train wreck. Very high chance of regressions, but probably only for the AOs listed above. The rest you can figure out from reading the diff.
Diffstat (limited to 'audio/out/internal.h')
-rw-r--r--audio/out/internal.h118
1 files changed, 52 insertions, 66 deletions
diff --git a/audio/out/internal.h b/audio/out/internal.h
index 71f98304be..15ffd82e57 100644
--- a/audio/out/internal.h
+++ b/audio/out/internal.h
@@ -48,9 +48,7 @@ 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).
+ // Set by the driver on init.
// This value is in complete samples (i.e. 1 for stereo means 1 sample
// for both channels each).
// Used for push based API only.
@@ -82,6 +80,18 @@ struct ao {
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.
+ 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 underrun; // if in underrun state (signals both accidental
+ // underruns and normal playback end); cleared by AO
+ // driver on reset() calls
+};
+
/* Note:
*
* In general, there are two types of audio drivers:
@@ -89,38 +99,32 @@ bool init_buffer_post(struct ao *ao);
* 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
+ * start
+ * Optional for both types:
+ * control
+ * 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
- * get_space
- * play
- * get_delay
- * pause
- * resume
+ * write
+ * get_state
* Optional:
- * control
- * wait
- * wakeup
- * b) ->play must be NULL. ->resume must be provided, and should make the
+ * set_pause
+ * 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.
@@ -130,16 +134,9 @@ 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;
- // Whether underruns are strictly _always_ reported via ao_underrun_event().
- // Do not set this to true if underruns may be missed in some way. If the
- // AO can't guarantee to play silence after underruns, it may be better not
- // to set this.
- // If not set, the generic buffer code will report an underrun if the buffer
- // becomes empty.
- bool reports_underruns;
// 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.
@@ -147,36 +144,29 @@ 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
+ // Stop all audio playback, clear buffers, back to state after init().
+ // Optional for pull AOs.
void (*reset)(struct ao *ao);
- // push based: see ao_pause()
- void (*pause)(struct ao *ao);
- // push based: see ao_resume()
+ // 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; unpausing always works)
+ 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);
- // 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_playthread() if a period boundary
+ // is crossed, or playback stops due to external reasons
+ // (including underruns or device removal)
+ 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
@@ -204,13 +194,7 @@ 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);
-bool ao_underrun_event(struct ao *ao);
bool ao_chmap_sel_adjust(struct ao *ao, const struct mp_chmap_sel *s,
struct mp_chmap *map);
@@ -238,6 +222,8 @@ 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_playthread(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);