From af05a71bc3a7d7d9aa6523b1760afaf3a074b68f Mon Sep 17 00:00:00 2001 From: Peter Bennett Date: Sun, 19 May 2019 15:27:41 -0400 Subject: [PATCH] Android: Fix deadlock in AudioTrack processing When exiting during a pause, there was an infinite wait for the output thread to end if there was data buffered. Now fixed. Refs #13446 --- .../mythtv/audio/AudioOutputAudioTrack.java | 55 +++++++++++-------- .../libmyth/audio/audiooutputaudiotrack.cpp | 25 ++++++++- .../libmyth/audio/audiooutputaudiotrack.h | 2 + 3 files changed, 59 insertions(+), 23 deletions(-) diff --git a/mythtv/android-package-source/src/org/mythtv/audio/AudioOutputAudioTrack.java b/mythtv/android-package-source/src/org/mythtv/audio/AudioOutputAudioTrack.java index 7f2b7f296b3..ffa76bc9801 100644 --- a/mythtv/android-package-source/src/org/mythtv/audio/AudioOutputAudioTrack.java +++ b/mythtv/android-package-source/src/org/mythtv/audio/AudioOutputAudioTrack.java @@ -26,6 +26,7 @@ public class AudioOutputAudioTrack int latencyCount; boolean isSettled; boolean isBufferInFlux; + boolean isOutputThreadStarted; public AudioOutputAudioTrack(int encoding, int sampleRate, int bufferSize, int channels) { @@ -94,36 +95,34 @@ public int write(byte[] audioData, int sizeInBytes) int written = 0; int ret = 0; int i; - if (player != null) + while (buf.hasRemaining()) { - while (buf.hasRemaining()) + synchronized(syncBuffer) { + // get out if we should not be here + if (player == null || !isOutputThreadStarted) + break; ret = player.write(buf, buf.remaining(), AudioTrack.WRITE_NON_BLOCKING); if (ret < 0) { break; } written += ret; - synchronized(syncBuffer) - { - bytesWritten += ret; - lastwritetime = System.nanoTime(); - // Note that only after this method returns is this data - // removed from the caller's buffer. - // bufferedBytes may be negative because actually some - // data still in the "Audio circular buffer" may have - // already played. - bufferedBytes = buf.remaining() - sizeInBytes; - } - try - { - Thread.sleep(10); - } - catch (InterruptedException ex) {} + bytesWritten += ret; + lastwritetime = System.nanoTime(); + // Note that only after this method returns is this data + // removed from the caller's buffer. + // bufferedBytes may be negative because actually some + // data still in the "Audio circular buffer" may have + // already played. + bufferedBytes = buf.remaining() - sizeInBytes; + } + try + { + Thread.sleep(10); } + catch (InterruptedException ex) {} } - else - written = AudioTrack.ERROR; synchronized(syncBuffer) { // After we return to caller, the data will be removed from @@ -216,9 +215,21 @@ public void pause (boolean doPause) public void release () { - if (player != null) + if (player == null) + return; + + synchronized(syncBuffer) + { + pause(true); + player.flush(); player.release(); - player = null; + player = null; + } + } + + public void setOutputThread (boolean isStarted) + { + isOutputThreadStarted = isStarted; } } diff --git a/mythtv/libs/libmyth/audio/audiooutputaudiotrack.cpp b/mythtv/libs/libmyth/audio/audiooutputaudiotrack.cpp index 1d3d7cdf7b2..df54d5f9337 100644 --- a/mythtv/libs/libmyth/audio/audiooutputaudiotrack.cpp +++ b/mythtv/libs/libmyth/audio/audiooutputaudiotrack.cpp @@ -56,7 +56,6 @@ AudioOutputAudioTrack::AudioOutputAudioTrack(const AudioSettings &settings) : AudioOutputAudioTrack::~AudioOutputAudioTrack() { KillAudio(); - CloseDevice(); } bool AudioOutputAudioTrack::OpenDevice() @@ -295,3 +294,27 @@ void AudioOutputAudioTrack::SetSourceBitrate(int rate) } } } + +bool AudioOutputAudioTrack::StartOutputThread(void) +{ + QAndroidJniEnvironment env; + if (m_audioTrack) + { + m_audioTrack->callMethod("setOutputThread","(Z)V",true); + ANDROID_EXCEPTION_CLEAR + } + + return AudioOutputBase::StartOutputThread(); +} + +void AudioOutputAudioTrack::StopOutputThread(void) +{ + QAndroidJniEnvironment env; + if (m_audioTrack) + { + m_audioTrack->callMethod("setOutputThread","(Z)V",false); + ANDROID_EXCEPTION_CLEAR + } + + AudioOutputBase::StopOutputThread(); +} diff --git a/mythtv/libs/libmyth/audio/audiooutputaudiotrack.h b/mythtv/libs/libmyth/audio/audiooutputaudiotrack.h index 9f407448945..ab8d383c838 100644 --- a/mythtv/libs/libmyth/audio/audiooutputaudiotrack.h +++ b/mythtv/libs/libmyth/audio/audiooutputaudiotrack.h @@ -35,6 +35,8 @@ class AudioOutputAudioTrack : public AudioOutputBase int GetBufferedOnSoundcard(void) const override; // AudioOutputBase AudioOutputSettings* GetOutputSettings(bool digital) override; // AudioOutputBase void SetSourceBitrate(int rate) override; // AudioOutputBase + bool StartOutputThread(void) override; // AudioOutputBase + void StopOutputThread(void) override; // AudioOutputBase QAndroidJniObject *m_audioTrack {nullptr}; int m_bitsPer10Frames {0}; };