@@ -318,8 +318,18 @@ alsa_set_stream_state(cubeb_stream * stm, enum stream_state state)
318318 poll_wake (ctx );
319319}
320320
321+ static void
322+ alsa_set_draining (cubeb_stream * stm )
323+ {
324+ alsa_set_stream_state (stm , DRAINING );
325+ if (stm -> stream_type == SND_PCM_STREAM_PLAYBACK && stm -> other_stream &&
326+ stm -> other_stream -> state == RUNNING ) {
327+ alsa_set_stream_state (stm -> other_stream , DRAINING );
328+ }
329+ }
330+
321331static enum stream_state
322- alsa_process_stream (cubeb_stream * stm )
332+ alsa_process_stream (cubeb_stream * stm , int other_stream_running )
323333{
324334 unsigned short revents ;
325335 snd_pcm_sframes_t avail ;
@@ -376,6 +386,7 @@ alsa_process_stream(cubeb_stream * stm)
376386 (!stm -> other_stream ||
377387 stm -> other_stream -> bufframes < stm -> other_stream -> buffer_size )) {
378388 snd_pcm_sframes_t wrote = stm -> bufframes ;
389+ snd_pcm_sframes_t requested ;
379390 struct cubeb_stream * mainstm = stm -> other_stream ? stm -> other_stream : stm ;
380391 void * other_buffer = stm -> other_stream ? stm -> other_stream -> buffer +
381392 stm -> other_stream -> bufframes
@@ -388,6 +399,7 @@ alsa_process_stream(cubeb_stream * stm)
388399 wrote = stm -> other_stream -> buffer_size - stm -> other_stream -> bufframes ;
389400 }
390401
402+ requested = wrote ;
391403 pthread_mutex_unlock (& stm -> mutex );
392404 wrote = stm -> data_callback (mainstm , stm -> user_ptr , stm -> buffer ,
393405 other_buffer , wrote );
@@ -401,24 +413,35 @@ alsa_process_stream(cubeb_stream * stm)
401413 if (stm -> other_stream ) {
402414 stm -> other_stream -> bufframes += wrote ;
403415 }
416+ if (wrote < requested ) {
417+ if (!stm -> other_stream ) {
418+ pthread_mutex_unlock (& stm -> mutex );
419+ return INACTIVE ;
420+ }
421+ draining = 1 ;
422+ set_timeout (& stm -> drain_timeout , 0 );
423+ }
404424 }
405425 }
406426
407427 /* Playback: Don't have enough data? Let's ask for more. */
408428 if (stm -> stream_type == SND_PCM_STREAM_PLAYBACK &&
409429 avail > (snd_pcm_sframes_t )stm -> bufframes &&
410- (!stm -> other_stream || stm -> other_stream -> bufframes > 0 )) {
430+ (!stm -> other_stream ||
431+ (other_stream_running && stm -> other_stream -> bufframes > 0 ))) {
411432 long got = avail - stm -> bufframes ;
412433 void * other_buffer = stm -> other_stream ? stm -> other_stream -> buffer : NULL ;
413434 char * buftail =
414435 stm -> buffer + WRAP (snd_pcm_frames_to_bytes )(stm -> pcm , stm -> bufframes );
436+ long requested ;
415437
416438 /* Correct read size to the other stream available frames */
417439 if (stm -> other_stream &&
418440 got > (snd_pcm_sframes_t )stm -> other_stream -> bufframes ) {
419441 got = stm -> other_stream -> bufframes ;
420442 }
421443
444+ requested = got ;
422445 pthread_mutex_unlock (& stm -> mutex );
423446 got = stm -> data_callback (stm , stm -> user_ptr , other_buffer , buftail , got );
424447 pthread_mutex_lock (& stm -> mutex );
@@ -431,6 +454,9 @@ alsa_process_stream(cubeb_stream * stm)
431454 if (stm -> other_stream ) {
432455 stream_buffer_decrement (stm -> other_stream , got );
433456 }
457+ if (got < requested ) {
458+ draining = 1 ;
459+ }
434460 }
435461 }
436462
@@ -446,7 +472,7 @@ alsa_process_stream(cubeb_stream * stm)
446472 stm -> bufframes = avail ;
447473
448474 /* Mark as draining, unless we're waiting for capture */
449- if (!stm -> other_stream || stm -> other_stream -> bufframes > 0 ) {
475+ if (!stm -> other_stream || draining || stm -> other_stream -> bufframes > 0 ) {
450476 set_timeout (& stm -> drain_timeout , drain_time * 1000 );
451477
452478 draining = 1 ;
@@ -524,7 +550,10 @@ alsa_run(cubeb * ctx)
524550 stm = ctx -> streams [i ];
525551 if (stm && stm -> state == DRAINING ) {
526552 r = ms_until (& stm -> drain_timeout );
527- if (r >= 0 && timeout > r ) {
553+ if (r < 0 ) {
554+ r = 0 ;
555+ }
556+ if (timeout > r ) {
528557 timeout = r ;
529558 }
530559 }
@@ -552,11 +581,20 @@ alsa_run(cubeb * ctx)
552581 https://github.com/kinetiknz/cubeb/issues/135. */
553582 if (stm && stm -> state == RUNNING && stm -> fds &&
554583 any_revents (stm -> fds , stm -> nfds )) {
584+ int other_stream_running =
585+ !stm -> other_stream || stm -> other_stream -> state == RUNNING ;
555586 alsa_set_stream_state (stm , PROCESSING );
556587 pthread_mutex_unlock (& ctx -> mutex );
557- state = alsa_process_stream (stm );
588+ state = alsa_process_stream (stm , other_stream_running );
558589 pthread_mutex_lock (& ctx -> mutex );
559- alsa_set_stream_state (stm , state );
590+ if (state == DRAINING ) {
591+ alsa_set_draining (stm );
592+ } else if (state == INACTIVE ) {
593+ alsa_set_stream_state (stm , state );
594+ stm -> state_callback (stm , stm -> user_ptr , CUBEB_STATE_STOPPED );
595+ } else {
596+ alsa_set_stream_state (stm , state );
597+ }
560598 }
561599 }
562600 } else if (r == 0 ) {
@@ -565,7 +603,10 @@ alsa_run(cubeb * ctx)
565603 if (stm ) {
566604 if (stm -> state == DRAINING && ms_since (& stm -> drain_timeout ) >= 0 ) {
567605 alsa_set_stream_state (stm , INACTIVE );
568- stm -> state_callback (stm , stm -> user_ptr , CUBEB_STATE_DRAINED );
606+ if (!stm -> other_stream ||
607+ stm -> stream_type == SND_PCM_STREAM_PLAYBACK ) {
608+ stm -> state_callback (stm , stm -> user_ptr , CUBEB_STATE_DRAINED );
609+ }
569610 } else if (stm -> state == RUNNING &&
570611 ms_since (& stm -> last_activity ) > CUBEB_WATCHDOG_MS ) {
571612 alsa_set_stream_state (stm , ERROR );
0 commit comments