diff options
Diffstat (limited to 'audio/out/buffer.c')
-rw-r--r-- | audio/out/buffer.c | 61 |
1 files changed, 39 insertions, 22 deletions
diff --git a/audio/out/buffer.c b/audio/out/buffer.c index 5b8b523..97f7ea1 100644 --- a/audio/out/buffer.c +++ b/audio/out/buffer.c @@ -41,7 +41,7 @@ struct buffer_state { mp_mutex lock; mp_cond wakeup; - // Playthread sleep + // AO thread sleep mp_mutex pt_lock; mp_cond pt_wakeup; @@ -62,6 +62,11 @@ struct buffer_state { bool paused; // logically paused 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; @@ -78,9 +83,9 @@ struct buffer_state { bool terminate; // exit thread }; -static MP_THREAD_VOID playthread(void *arg); +static MP_THREAD_VOID ao_thread(void *arg); -void ao_wakeup_playthread(struct ao *ao) +void ao_wakeup(struct ao *ao) { struct buffer_state *p = ao->buffer_state; mp_mutex_lock(&p->pt_lock); @@ -173,8 +178,8 @@ static int read_buffer(struct ao *ao, void **data, int samples, bool *eof, return pos; } -static int ao_read_data_unlocked(struct ao *ao, void **data, int samples, - int64_t out_time_ns, bool pad_silence) +static int ao_read_data_locked(struct ao *ao, void **data, int samples, + int64_t out_time_ns, bool pad_silence) { struct buffer_state *p = ao->buffer_state; assert(!ao->driver->write); @@ -208,7 +213,7 @@ int ao_read_data(struct ao *ao, void **data, int samples, int64_t out_time_ns) mp_mutex_lock(&p->lock); - int pos = ao_read_data_unlocked(ao, data, samples, out_time_ns, true); + int pos = ao_read_data_locked(ao, data, samples, out_time_ns, true); mp_mutex_unlock(&p->lock); @@ -224,7 +229,7 @@ int ao_read_data_nonblocking(struct ao *ao, void **data, int samples, int64_t ou if (mp_mutex_trylock(&p->lock)) return 0; - int pos = ao_read_data_unlocked(ao, data, samples, out_time_ns, false); + int pos = ao_read_data_locked(ao, data, samples, out_time_ns, false); mp_mutex_unlock(&p->lock); @@ -347,7 +352,7 @@ void ao_reset(struct ao *ao) ao->driver->reset(ao); if (wakeup) - ao_wakeup_playthread(ao); + ao_wakeup(ao); } // Initiate playback. This moves from the stop/underrun state to actually @@ -374,14 +379,14 @@ void ao_start(struct ao *ao) if (do_start) ao->driver->start(ao); - ao_wakeup_playthread(ao); + ao_wakeup(ao); } void ao_set_paused(struct ao *ao, bool paused, bool eof) { struct buffer_state *p = ao->buffer_state; 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, // 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->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. - do_reset = true; + do_change_state = true; p->streaming = false; } } @@ -416,7 +421,7 @@ void ao_set_paused(struct ao *ao, bool paused, bool eof) p->hw_paused = false; } else { if (!p->streaming) - do_start = true; + do_change_state = true; p->streaming = true; } wakeup = true; @@ -425,13 +430,25 @@ void ao_set_paused(struct ao *ao, bool paused, bool eof) mp_mutex_unlock(&p->lock); - if (do_reset) - ao->driver->reset(ao); - if (do_start) - ao->driver->start(ao); + 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); + else + ao->driver->start(ao); + } + } if (wakeup) - ao_wakeup_playthread(ao); + ao_wakeup(ao); } // Whether audio is playing. This means that there is still data in the buffers, @@ -486,7 +503,7 @@ void ao_drain(struct ao *ao) static void wakeup_filters(void *ctx) { struct ao *ao = ctx; - ao_wakeup_playthread(ao); + ao_wakeup(ao); } void ao_uninit(struct ao *ao) @@ -561,7 +578,7 @@ bool init_buffer_post(struct ao *ao) mp_filter_graph_set_wakeup_cb(p->filter_root, wakeup_filters, ao); p->thread_valid = true; - if (mp_thread_create(&p->thread, playthread, ao)) { + if (mp_thread_create(&p->thread, ao_thread, ao)) { p->thread_valid = false; return false; } @@ -684,7 +701,7 @@ eof: return true; } -static MP_THREAD_VOID playthread(void *arg) +static MP_THREAD_VOID ao_thread(void *arg) { struct ao *ao = arg; struct buffer_state *p = ao->buffer_state; @@ -731,6 +748,6 @@ void ao_unblock(struct ao *ao) mp_mutex_lock(&p->lock); p->initial_unblocked = true; mp_mutex_unlock(&p->lock); - ao_wakeup_playthread(ao); + ao_wakeup(ao); } } |