Skip to content

Commit 8dd41fb

Browse files
narayankAndroid (Google) Code Review
authored andcommitted
Merge "Don't wait indefinitely for audio tracks to finish playing."
2 parents e83f771 + 69bc1b2 commit 8dd41fb

File tree

1 file changed

+49
-6
lines changed

1 file changed

+49
-6
lines changed

core/java/android/speech/tts/AudioPlaybackHandler.java

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)