@@ -584,12 +584,19 @@ static ssize_t coreaudio_write(void *data, const void *buf_, size_t len)
584584
585585 if (samples > 0 )
586586 {
587- /* Buffer full, wait for audio callback to drain some.
588- * Use a timeout as a safety net in case audio stalls. */
589- dispatch_time_t timeout = dispatch_time (
590- DISPATCH_TIME_NOW , 500 * NSEC_PER_MSEC );
591- if (dispatch_semaphore_wait (dev -> sema , timeout ) != 0 )
592- break ; /* Timeout - audio might be stalled */
587+ /* If the audio unit has stopped (e.g. audio session interrupted
588+ * by a phone call), bail out - the callback will never drain. */
589+ UInt32 running = 0 ;
590+ UInt32 size = sizeof (running );
591+ if (AudioUnitGetProperty (dev -> dev ,
592+ kAudioOutputUnitProperty_IsRunning ,
593+ kAudioUnitScope_Global , 0 ,
594+ & running , & size ) == noErr && !running )
595+ break ;
596+ /* Brief timeout as safety net for the race where the unit
597+ * stops during the wait; we'll re-check on the next iteration. */
598+ dispatch_semaphore_wait (dev -> sema ,
599+ dispatch_time (DISPATCH_TIME_NOW , 100 * NSEC_PER_MSEC ));
593600 }
594601 }
595602
@@ -686,10 +693,15 @@ static ssize_t coreaudio_write_raw(void *data, const int16_t *samples,
686693
687694 if (out_samples > 0 )
688695 {
689- dispatch_time_t timeout = dispatch_time (
690- DISPATCH_TIME_NOW , 500 * NSEC_PER_MSEC );
691- if (dispatch_semaphore_wait (dev -> sema , timeout ) != 0 )
696+ UInt32 running = 0 ;
697+ UInt32 sz = sizeof (running );
698+ if (AudioUnitGetProperty (dev -> dev ,
699+ kAudioOutputUnitProperty_IsRunning ,
700+ kAudioUnitScope_Global , 0 ,
701+ & running , & sz ) == noErr && !running )
692702 break ;
703+ dispatch_semaphore_wait (dev -> sema ,
704+ dispatch_time (DISPATCH_TIME_NOW , 100 * NSEC_PER_MSEC ));
693705 }
694706 }
695707 }
0 commit comments