Skip to content

Commit

Permalink
Wait in release() for prepareAsync() to finish first
Browse files Browse the repository at this point in the history
  • Loading branch information
protyposis committed Dec 21, 2016
1 parent 9723716 commit c6a6d30
Showing 1 changed file with 40 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.CountDownLatch;

/**
* Created by maguggen on 04.06.2014.
Expand Down Expand Up @@ -189,6 +190,14 @@ private enum State {
private State mCurrentState;

private final Object PT_SYNC = new Object();
/**
* A lock to make sure that a release(), called during prepareAsync(), always waits until
* prepareAsync() is finished before it does the actual releasing.
* A CountDownLatch is used because a normal Lock cannot be locked and unlocked from different
* threads (prepareAsync caller thread vs. prepareAsync async execution thread).
* TODO do the same for stop()/reset()
*/
private CountDownLatch mPrepareAsyncReleaseSyncLock;

public MediaPlayer() {
mPlaybackThread = null;
Expand Down Expand Up @@ -300,6 +309,11 @@ public void onBuffering(MediaCodecDecoder decoder) {
}
};

if(mCurrentState == State.RELEASING) {
// release() has already been called, drop out of prepareAsync() (can only happen with async prepare)
return;
}

mDecoders = new Decoders();

if(mVideoTrackIndex != MediaCodecDecoder.INDEX_NONE) {
Expand Down Expand Up @@ -349,8 +363,8 @@ public void onBuffering(MediaCodecDecoder decoder) {
mEventHandler.sendMessage(mEventHandler.obtainMessage(MEDIA_SET_VIDEO_SIZE, width, height));
}

if(mCurrentState == State.RELEASING || mCurrentState == State.RELEASED) {
// Cancel preparation if release was called in between
if(mCurrentState == State.RELEASING) {
// release() has already been called, drop out of prepareAsync()
return;
}

Expand All @@ -372,8 +386,8 @@ public void onBuffering(MediaCodecDecoder decoder) {
}

synchronized(PT_SYNC) {
if(mCurrentState == State.RELEASING || mCurrentState == State.RELEASED) {
// Cancel preparation if release was called in between
if(mCurrentState == State.RELEASING) {
// release() has already been called, drop out of prepareAsync()
return;
}

Expand Down Expand Up @@ -405,6 +419,10 @@ public void prepareAsync() throws IllegalStateException {
throw new IllegalStateException();
}

// Create a new lock for release() to wait until prepareAsync is finished
// A new instance needs to be created each time because it can only be used once
mPrepareAsyncReleaseSyncLock = new CountDownLatch(1);

mCurrentState = State.PREPARING;

/* Running prepare() in an AsyncTask leads to severe performance degradations, unless the
Expand Down Expand Up @@ -438,6 +456,9 @@ public void run() {
Log.e(TAG, "prepareAsync() failed: surface might be gone", e);
mEventHandler.sendMessage(mEventHandler.obtainMessage(MEDIA_ERROR,
MEDIA_ERROR_UNKNOWN, 0));
} finally {
// Free the lock to let release() continue (if called while preparing)
mPrepareAsyncReleaseSyncLock.countDown();
}
}
}).start();
Expand Down Expand Up @@ -607,8 +628,22 @@ public void stop() {

public void release() {
mCurrentState = State.RELEASING;

if(mPrepareAsyncReleaseSyncLock != null) {
// This lock does only exist if prepareAsync() has been called before
try {
// Wait for prepareAsync() to finish before actually releasing stuff
mPrepareAsyncReleaseSyncLock.await();
} catch (InterruptedException e) {
// nothing to do here
} finally {
mPrepareAsyncReleaseSyncLock = null;
}
}

stop();
mCurrentState = State.RELEASED;
Log.d(TAG, "released");
}

public void reset() {
Expand Down Expand Up @@ -898,7 +933,7 @@ private void release() {
}
}

Log.d(TAG, "released");
Log.d(TAG, "PlaybackThread released");
}

@Override
Expand Down

0 comments on commit c6a6d30

Please sign in to comment.