@@ -450,6 +450,19 @@ private void handleSynthesisDone(MessageParams msg) {
450450 */
451451 private static final long MIN_SLEEP_TIME_MS = 20 ;
452452
453+ /**
454+ * The maximum increment of time to sleep while waiting for an audiotrack
455+ * to finish playing.
456+ */
457+ private static final long MAX_SLEEP_TIME_MS = 2500 ;
458+
459+ /**
460+ * The maximum amount of time to wait for an audio track to make progress while
461+ * it remains in PLAYSTATE_PLAYING. This should never happen in normal usage, but
462+ * could happen in exceptional circumstances like a media_server crash.
463+ */
464+ private static final long MAX_PROGRESS_WAIT_MS = MAX_SLEEP_TIME_MS ;
465+
453466 private static void blockUntilDone (SynthesisMessageParams params ) {
454467 if (params .mAudioTrack == null || params .mBytesWritten <= 0 ) {
455468 return ;
@@ -490,16 +503,34 @@ private static void blockUntilCompletion(SynthesisMessageParams params) {
490503 final AudioTrack audioTrack = params .mAudioTrack ;
491504 final int lengthInFrames = params .mBytesWritten / params .mBytesPerFrame ;
492505
506+ int previousPosition = -1 ;
493507 int currentPosition = 0 ;
494- while (( currentPosition = audioTrack . getPlaybackHeadPosition ()) < lengthInFrames ) {
495- if ( audioTrack . getPlayState () != AudioTrack . PLAYSTATE_PLAYING ) {
496- break ;
497- }
508+ long blockedTimeMs = 0 ;
509+
510+ while (( currentPosition = audioTrack . getPlaybackHeadPosition ()) < lengthInFrames &&
511+ audioTrack . getPlayState () == AudioTrack . PLAYSTATE_PLAYING ) {
498512
499513 final long estimatedTimeMs = ((lengthInFrames - currentPosition ) * 1000 ) /
500514 audioTrack .getSampleRate ();
501-
502- final long sleepTimeMs = Math .max (estimatedTimeMs , MIN_SLEEP_TIME_MS );
515+ final long sleepTimeMs = clip (estimatedTimeMs , MIN_SLEEP_TIME_MS , MAX_SLEEP_TIME_MS );
516+
517+ // Check if the audio track has made progress since the last loop
518+ // iteration. We should then add in the amount of time that was
519+ // spent sleeping in the last iteration.
520+ if (currentPosition == previousPosition ) {
521+ // This works only because the sleep time that would have been calculated
522+ // would be the same in the previous iteration too.
523+ blockedTimeMs += sleepTimeMs ;
524+ // If we've taken too long to make progress, bail.
525+ if (blockedTimeMs > MAX_PROGRESS_WAIT_MS ) {
526+ Log .w (TAG , "Waited unsuccessfully for " + MAX_PROGRESS_WAIT_MS + "ms " +
527+ "for AudioTrack to make progress, Aborting" );
528+ break ;
529+ }
530+ } else {
531+ blockedTimeMs = 0 ;
532+ }
533+ previousPosition = currentPosition ;
503534
504535 if (DBG ) Log .d (TAG , "About to sleep for : " + sleepTimeMs + " ms," +
505536 " Playback position : " + currentPosition + ", Length in frames : "
@@ -512,6 +543,18 @@ private static void blockUntilCompletion(SynthesisMessageParams params) {
512543 }
513544 }
514545
546+ private static final long clip (long value , long min , long max ) {
547+ if (value < min ) {
548+ return min ;
549+ }
550+
551+ if (value > max ) {
552+ return max ;
553+ }
554+
555+ return value ;
556+ }
557+
515558 private static AudioTrack createStreamingAudioTrack (SynthesisMessageParams params ) {
516559 final int channelConfig = getChannelConfig (params .mChannelCount );
517560 final int sampleRateInHz = params .mSampleRateInHz ;
0 commit comments