ao: set_pause for pull based ao

This commit is contained in:
Misaki Kasumi 2024-03-26 04:08:13 +08:00 committed by sfan5
parent 8d85627aad
commit 93a924a553
2 changed files with 29 additions and 10 deletions

View File

@ -62,6 +62,11 @@ struct buffer_state {
bool paused; // logically paused bool paused; // logically paused
int64_t end_time_ns; // absolute output time of last played sample int64_t end_time_ns; // absolute output time of last played sample
int64_t queued_time_ns; // duration of samples that have been queued to
// the device but have not been played.
// This field is only set in ao_set_paused(),
// and is considered as a temporary solution;
// DO NOT USE IT IN OTHER PLACES.
bool initial_unblocked; bool initial_unblocked;
@ -381,7 +386,7 @@ void ao_set_paused(struct ao *ao, bool paused, bool eof)
{ {
struct buffer_state *p = ao->buffer_state; struct buffer_state *p = ao->buffer_state;
bool wakeup = false; bool wakeup = false;
bool do_reset = false, do_start = false; bool do_change_state = false;
// If we are going to pause on eof and ao is still playing, // If we are going to pause on eof and ao is still playing,
// be sure to drain the ao first for gapless. // be sure to drain the ao first for gapless.
@ -402,9 +407,9 @@ void ao_set_paused(struct ao *ao, bool paused, bool eof)
p->streaming = false; p->streaming = false;
p->recover_pause = !ao->untimed; p->recover_pause = !ao->untimed;
} }
} else if (ao->driver->reset) { } else if (ao->driver->reset || ao->driver->set_pause) {
// See ao_reset() why this is done outside of the lock. // See ao_reset() why this is done outside of the lock.
do_reset = true; do_change_state = true;
p->streaming = false; p->streaming = false;
} }
} }
@ -416,7 +421,7 @@ void ao_set_paused(struct ao *ao, bool paused, bool eof)
p->hw_paused = false; p->hw_paused = false;
} else { } else {
if (!p->streaming) if (!p->streaming)
do_start = true; do_change_state = true;
p->streaming = true; p->streaming = true;
} }
wakeup = true; wakeup = true;
@ -425,10 +430,22 @@ void ao_set_paused(struct ao *ao, bool paused, bool eof)
mp_mutex_unlock(&p->lock); mp_mutex_unlock(&p->lock);
if (do_reset) if (do_change_state) {
if (ao->driver->set_pause) {
if (paused) {
ao->driver->set_pause(ao, true);
p->queued_time_ns = p->end_time_ns - mp_time_ns();
} else {
p->end_time_ns = p->queued_time_ns + mp_time_ns();
ao->driver->set_pause(ao, false);
}
} else {
if (paused)
ao->driver->reset(ao); ao->driver->reset(ao);
if (do_start) else
ao->driver->start(ao); ao->driver->start(ao);
}
}
if (wakeup) if (wakeup)
ao_wakeup_playthread(ao); ao_wakeup_playthread(ao);

View File

@ -108,6 +108,7 @@ struct mp_pcm_state {
* start * start
* Optional for both types: * Optional for both types:
* control * control
* set_pause
* a) ->write is called to queue audio. push.c creates a thread to regularly * 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 * refill audio device buffers with ->write, but all driver functions are
* always called under an exclusive lock. * always called under an exclusive lock.
@ -115,8 +116,6 @@ struct mp_pcm_state {
* reset * reset
* write * write
* get_state * get_state
* Optional:
* set_pause
* b) ->write must be NULL. ->start must be provided, and should make the * b) ->write must be NULL. ->start must be provided, and should make the
* audio API start calling the audio callback. Your audio callback should * audio API start calling the audio callback. Your audio callback should
* in turn call ao_read_data() to get audio data. Most functions are * in turn call ao_read_data() to get audio data. Most functions are
@ -149,6 +148,9 @@ struct ao_driver {
// Stop all audio playback, clear buffers, back to state after init(). // Stop all audio playback, clear buffers, back to state after init().
// Optional for pull AOs. // Optional for pull AOs.
void (*reset)(struct ao *ao); 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(). // push based: set pause state. Only called after start() and before reset().
// returns success (this is intended for paused=true; if it // returns success (this is intended for paused=true; if it
// returns false, playback continues, and the core emulates via // returns false, playback continues, and the core emulates via