This commit adds a state `hw_paused` for pull-based AO. `driver->set_paused(false)` is only called if `hw_paused` is true. `hw_paused` is cleared after `ao_reset`, so `set_paused` will not be called after a reset; instead, `driver->start()` will be called, which properly starts the AO.
Unified · Split
| @@ -59,6 +59,7 @@ struct buffer_state { · 58 unmodified lines | |||
| 59 | bool streaming; // AO streaming active | 59 | bool streaming; // AO streaming active |
| 60 | bool playing; // logically playing audio from buffer | 60 | bool playing; // logically playing audio from buffer |
| 61 | bool paused; // logically paused | 61 | bool paused; // logically paused |
| 62 | bool hw_paused; // driver->set_pause() was used successfully | ||
| 62 | 63 | ||
| 63 | int64_t end_time_ns; // absolute output time of last played sample | 64 | int64_t end_time_ns; // absolute output time of last played sample |
| 64 | int64_t queued_time_ns; // duration of samples that have been queued to | 65 | int64_t queued_time_ns; // duration of samples that have been queued to |
| @@ -70,7 +71,6 @@ struct buffer_state { · 5 unmodified lines | |||
| 70 | bool initial_unblocked; | 71 | bool initial_unblocked; |
| 71 | 72 | ||
| 72 | // "Push" AOs only (AOs with driver->write). | 73 | // "Push" AOs only (AOs with driver->write). |
| 73 | bool hw_paused; // driver->set_pause() was used successfully | ||
| 74 | bool recover_pause; // non-hw_paused: needs to recover delay | 74 | bool recover_pause; // non-hw_paused: needs to recover delay |
| 75 | struct mp_pcm_state prepause_state; | 75 | struct mp_pcm_state prepause_state; |
| 76 | mp_thread thread; // thread shoveling data to AO | 76 | mp_thread thread; // thread shoveling data to AO |
| @@ -386,6 +386,7 @@ void ao_set_paused(struct ao *ao, bool paused, bool eof) · 309 unmodified lines | |||
| 386 | struct buffer_state *p = ao->buffer_state; | 386 | struct buffer_state *p = ao->buffer_state; |
| 387 | bool wakeup = false; | 387 | bool wakeup = false; |
| 388 | bool do_change_state = false; | 388 | bool do_change_state = false; |
| 389 | bool is_hw_paused; | ||
| 389 | 390 | ||
| 390 | // If we are going to pause on eof and ao is still playing, | 391 | // If we are going to pause on eof and ao is still playing, |
| 391 | // be sure to drain the ao first for gapless. | 392 | // be sure to drain the ao first for gapless. |
| @@ -410,6 +411,7 @@ void ao_set_paused(struct ao *ao, bool paused, bool eof) · 18 unmodified lines | |||
| 410 | // See ao_reset() why this is done outside of the lock. | 411 | // See ao_reset() why this is done outside of the lock. |
| 411 | do_change_state = true; | 412 | do_change_state = true; |
| 412 | p->streaming = false; | 413 | p->streaming = false; |
| 414 | is_hw_paused = p->hw_paused = !!ao->driver->set_pause; | ||
| 413 | } | 415 | } |
| 414 | } | 416 | } |
| 415 | wakeup = true; | 417 | wakeup = true; |
| @@ -422,6 +424,8 @@ void ao_set_paused(struct ao *ao, bool paused, bool eof) · 6 unmodified lines | |||
| 422 | if (!p->streaming) | 424 | if (!p->streaming) |
| 423 | do_change_state = true; | 425 | do_change_state = true; |
| 424 | p->streaming = true; | 426 | p->streaming = true; |
| 427 | is_hw_paused = p->hw_paused; | ||
| 428 | p->hw_paused = false; | ||
| 425 | } | 429 | } |
| 426 | wakeup = true; | 430 | wakeup = true; |
| 427 | } | 431 | } |
| @@ -430,7 +434,7 @@ void ao_set_paused(struct ao *ao, bool paused, bool eof) · 2 unmodified lines | |||
| 430 | mp_mutex_unlock(&p->lock); | 434 | mp_mutex_unlock(&p->lock); |
| 431 | 435 | ||
| 432 | if (do_change_state) { | 436 | if (do_change_state) { |
| 433 | if (ao->driver->set_pause) { | 437 | if (is_hw_paused) { |
| 434 | if (paused) { | 438 | if (paused) { |
| 435 | ao->driver->set_pause(ao, true); | 439 | ao->driver->set_pause(ao, true); |
| 436 | p->queued_time_ns = p->end_time_ns - mp_time_ns(); | 440 | p->queued_time_ns = p->end_time_ns - mp_time_ns(); |