Avoids WebRtcAudioTrack null pointer access at stop.

Example of new stop sequence:

PID   TID
5155  5189 I WebRtcAudioTrack: stopPlayout
5155  5189 I WebRtcAudioTrack: underrun count: 0
5155  5189 I WebRtcAudioTrack: stopThread
5155  5189 I WebRtcAudioTrack: Stopping the AudioTrackThread...

5155  5236 I WebRtcAudioTrack: Stopping and flushing the audio track...
5155  5236 I WebRtcAudioTrack: The audio track has now been stopped.

5155  5189 I WebRtcAudioTrack: AudioTrackThread has now been stopped.
5155  5189 I WebRtcAudioTrack: releaseAudioResources

BUG=b/64692432

Review-Url: https://codereview.webrtc.org/3001703002
Cr-Commit-Position: refs/heads/master@{#19370}
This commit is contained in:
henrika 2017-08-16 06:14:08 -07:00 committed by Commit Bot
parent 7ea6e59735
commit c103653113

View File

@ -152,8 +152,10 @@ public class WebRtcAudioTrack {
bytesWritten = writePreLollipop(audioTrack, byteBuffer, sizeInBytes);
}
if (bytesWritten != sizeInBytes) {
Logging.e(TAG, "AudioTrack.write failed: " + bytesWritten);
if (bytesWritten == AudioTrack.ERROR_INVALID_OPERATION) {
Logging.e(TAG, "AudioTrack.write played invalid number of bytes: " + bytesWritten);
// If a write() returns a negative value, an error has occurred.
// Stop playing and report an error in this case.
if (bytesWritten < 0) {
keepAlive = false;
reportWebRtcAudioTrackError("AudioTrack.write failed: " + bytesWritten);
}
@ -168,15 +170,16 @@ public class WebRtcAudioTrack {
// audioTrack.getPlaybackHeadPosition().
}
try {
if (audioTrack != null) {
audioTrack.stop();
}
} catch (IllegalStateException e) {
Logging.e(TAG, "AudioTrack.stop failed: " + e.getMessage());
// Stops playing the audio data. Since the instance was created in
// MODE_STREAM mode, audio will stop playing after the last buffer that
// was written has been played.
final AudioTrack at = audioTrack;
if (at != null) {
Logging.d(TAG, "Stopping the audio track...");
at.stop();
Logging.d(TAG, "The audio track has now been stopped.");
at.flush();
}
assertTrue(audioTrack.getPlayState() == AudioTrack.PLAYSTATE_STOPPED);
audioTrack.flush();
}
@TargetApi(21)
@ -188,7 +191,7 @@ public class WebRtcAudioTrack {
return audioTrack.write(byteBuffer.array(), byteBuffer.arrayOffset(), sizeInBytes);
}
// Stops the inner thread loop and also calls AudioTrack.stop().
// Stops the inner thread loop and also calls AudioTrack.pause() and flush().
// Does not block the calling thread.
public void stopThread() {
Logging.d(TAG, "stopThread");
@ -296,10 +299,18 @@ public class WebRtcAudioTrack {
assertTrue(audioThread != null);
logUnderrunCount();
audioThread.stopThread();
if (!ThreadUtils.joinUninterruptibly(audioThread, AUDIO_TRACK_THREAD_JOIN_TIMEOUT_MS)) {
Logging.e(TAG, "Join of AudioTrackThread timed out");
}
final Thread aThread = audioThread;
audioThread = null;
if (aThread != null) {
Logging.d(TAG, "Stopping the AudioTrackThread...");
aThread.interrupt();
if (!ThreadUtils.joinUninterruptibly(aThread, AUDIO_TRACK_THREAD_JOIN_TIMEOUT_MS)) {
Logging.e(TAG, "Join of AudioTrackThread timed out.");
}
Logging.d(TAG, "AudioTrackThread has now been stopped.");
}
releaseAudioResources();
return true;
}
@ -430,6 +441,7 @@ public class WebRtcAudioTrack {
// Releases the native AudioTrack resources.
private void releaseAudioResources() {
Logging.d(TAG, "releaseAudioResources");
if (audioTrack != null) {
audioTrack.release();
audioTrack = null;