Fix threading issue in BlockingAudioTrack.

This fixes the issue where one thread calls .stop() on
mAudioTrack that was released (or being released) by other thread.

Bug: 7029291
Change-Id: Ia6db803e8ee40379b63327acf578466127cfabcb
This commit is contained in:
Przemyslaw Szczepaniak
2012-08-23 17:45:46 +01:00
committed by Android (Google) Code Review
parent c5fd6e59db
commit 70574efd8f

View File

@@ -69,7 +69,8 @@ class BlockingAudioTrack {
// Need to be seen by stop() which can be called from another thread. mAudioTrack will be // Need to be seen by stop() which can be called from another thread. mAudioTrack will be
// set to null only after waitAndRelease(). // set to null only after waitAndRelease().
private volatile AudioTrack mAudioTrack; private Object mAudioTrackLock = new Object();
private AudioTrack mAudioTrack;
private volatile boolean mStopped; private volatile boolean mStopped;
BlockingAudioTrack(int streamType, int sampleRate, BlockingAudioTrack(int streamType, int sampleRate,
@@ -93,7 +94,9 @@ class BlockingAudioTrack {
public boolean init() { public boolean init() {
AudioTrack track = createStreamingAudioTrack(); AudioTrack track = createStreamingAudioTrack();
mAudioTrack = track; synchronized (mAudioTrackLock) {
mAudioTrack = track;
}
if (track == null) { if (track == null) {
return false; return false;
@@ -103,24 +106,34 @@ class BlockingAudioTrack {
} }
public void stop() { public void stop() {
AudioTrack track = mAudioTrack; synchronized (mAudioTrackLock) {
if (track != null) { if (mAudioTrack != null) {
track.stop(); mAudioTrack.stop();
}
mStopped = true;
} }
mStopped = true;
} }
public int write(byte[] data) { public int write(byte[] data) {
if (mAudioTrack == null || mStopped) { AudioTrack track = null;
synchronized (mAudioTrackLock) {
track = mAudioTrack;
}
if (track == null || mStopped) {
return -1; return -1;
} }
final int bytesWritten = writeToAudioTrack(mAudioTrack, data); final int bytesWritten = writeToAudioTrack(track, data);
mBytesWritten += bytesWritten; mBytesWritten += bytesWritten;
return bytesWritten; return bytesWritten;
} }
public void waitAndRelease() { public void waitAndRelease() {
AudioTrack track = mAudioTrack; AudioTrack track = null;
synchronized (mAudioTrackLock) {
track = mAudioTrack;
}
if (track == null) { if (track == null) {
if (DBG) Log.d(TAG, "Audio track null [duplicate call to waitAndRelease ?]"); if (DBG) Log.d(TAG, "Audio track null [duplicate call to waitAndRelease ?]");
return; return;
@@ -152,8 +165,10 @@ class BlockingAudioTrack {
// all data from the audioTrack has been sent to the mixer, so // all data from the audioTrack has been sent to the mixer, so
// it's safe to release at this point. // it's safe to release at this point.
if (DBG) Log.d(TAG, "Releasing audio track [" + track.hashCode() + "]"); if (DBG) Log.d(TAG, "Releasing audio track [" + track.hashCode() + "]");
synchronized(mAudioTrackLock) {
mAudioTrack = null;
}
track.release(); track.release();
mAudioTrack = null;
} }