Squashed commit of the following:

commit 427e927298449826bb5b98327b0c05957aa051e6
Author: Andreas Huber <andih@google.com>
Date:   Fri Feb 12 10:39:07 2010 -0800

    Fixing a race condition in AwesomePlayer and support for suspend/resume.

commit 96201a04b6657b6bd69ec6100f4de66aebcaa0b4
Author: Andreas Huber <andih@google.com>
Date:   Fri Feb 12 10:36:15 2010 -0800

    Protect MPEG4Source's sanity by properly locking.

related-to-bug: 2231576
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 5d2127b..41e6911 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -169,7 +169,8 @@
       mAudioPlayer(NULL),
       mFlags(0),
       mLastVideoBuffer(NULL),
-      mVideoBuffer(NULL) {
+      mVideoBuffer(NULL),
+      mSuspensionState(NULL) {
     CHECK_EQ(mClient.connect(), OK);
 
     DataSource::RegisterDefaultSniffers();
@@ -221,7 +222,11 @@
 status_t AwesomePlayer::setDataSource(
         const char *uri, const KeyedVector<String8, String8> *headers) {
     Mutex::Autolock autoLock(mLock);
+    return setDataSource_l(uri, headers);
+}
 
+status_t AwesomePlayer::setDataSource_l(
+        const char *uri, const KeyedVector<String8, String8> *headers) {
     reset_l();
 
     mUri = uri;
@@ -243,15 +248,22 @@
 
     reset_l();
 
-    sp<DataSource> source = new FileSource(fd, offset, length);
+    sp<DataSource> dataSource = new FileSource(fd, offset, length);
 
-    status_t err = source->initCheck();
+    status_t err = dataSource->initCheck();
 
     if (err != OK) {
         return err;
     }
 
-    sp<MediaExtractor> extractor = MediaExtractor::Create(source);
+    mFileSource = dataSource;
+
+    return setDataSource_l(dataSource);
+}
+
+status_t AwesomePlayer::setDataSource_l(
+        const sp<DataSource> &dataSource) {
+    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
 
     if (extractor == NULL) {
         return UNKNOWN_ERROR;
@@ -299,6 +311,26 @@
 
     cancelPlayerEvents();
 
+    if (mPrefetcher != NULL) {
+        CHECK_EQ(mPrefetcher->getStrongCount(), 1);
+    }
+    mPrefetcher.clear();
+
+    // Shutdown audio first, so that the respone to the reset request
+    // appears to happen instantaneously as far as the user is concerned
+    // If we did this later, audio would continue playing while we
+    // shutdown the video-related resources and the player appear to
+    // not be as responsive to a reset request.
+    mAudioSource.clear();
+
+    if (mTimeSource != mAudioPlayer) {
+        delete mTimeSource;
+    }
+    mTimeSource = NULL;
+
+    delete mAudioPlayer;
+    mAudioPlayer = NULL;
+
     mVideoRenderer.clear();
 
     if (mLastVideoBuffer) {
@@ -325,16 +357,6 @@
         IPCThreadState::self()->flushCommands();
     }
 
-    mAudioSource.clear();
-
-    if (mTimeSource != mAudioPlayer) {
-        delete mTimeSource;
-    }
-    mTimeSource = NULL;
-
-    delete mAudioPlayer;
-    mAudioPlayer = NULL;
-
     mDurationUs = -1;
     mFlags = 0;
     mVideoWidth = mVideoHeight = -1;
@@ -344,10 +366,13 @@
     mSeeking = false;
     mSeekTimeUs = 0;
 
-    mPrefetcher.clear();
-
     mUri.setTo("");
     mUriHeaders.clear();
+
+    mFileSource.clear();
+
+    delete mSuspensionState;
+    mSuspensionState = NULL;
 }
 
 void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
@@ -403,7 +428,10 @@
 
 status_t AwesomePlayer::play() {
     Mutex::Autolock autoLock(mLock);
+    return play_l();
+}
 
+status_t AwesomePlayer::play_l() {
     if (mFlags & PLAYING) {
         return OK;
     }
@@ -579,7 +607,10 @@
 
 status_t AwesomePlayer::getPosition(int64_t *positionUs) {
     Mutex::Autolock autoLock(mLock);
+    return getPosition_l(positionUs);
+}
 
+status_t AwesomePlayer::getPosition_l(int64_t *positionUs) {
     if (mVideoSource != NULL) {
         *positionUs = mVideoTimeUs;
     } else if (mAudioPlayer != NULL) {
@@ -697,7 +728,11 @@
 
 void AwesomePlayer::onVideoEvent() {
     Mutex::Autolock autoLock(mLock);
-
+    if (!mVideoEventPending) {
+        // The event has been cancelled in reset_l() but had already
+        // been scheduled for execution at that time.
+        return;
+    }
     mVideoEventPending = false;
 
     if (mSeeking) {
@@ -985,6 +1020,7 @@
 
     if (prefetcher != NULL) {
         prefetcher->prepare();
+        prefetcher.clear();
     }
 
     Mutex::Autolock autoLock(mLock);
@@ -1006,5 +1042,75 @@
     mPreparedCondition.broadcast();
 }
 
+status_t AwesomePlayer::suspend() {
+    LOGI("suspend");
+    Mutex::Autolock autoLock(mLock);
+
+    if (mSuspensionState != NULL) {
+        return INVALID_OPERATION;
+    }
+
+    while (mFlags & PREPARING) {
+        mPreparedCondition.wait(mLock);
+    }
+
+    SuspensionState *state = new SuspensionState;
+    state->mUri = mUri;
+    state->mUriHeaders = mUriHeaders;
+    state->mFileSource = mFileSource;
+
+    state->mFlags = mFlags & (PLAYING | LOOPING);
+    getPosition_l(&state->mPositionUs);
+
+    reset_l();
+
+    mSuspensionState = state;
+
+    return OK;
+}
+
+status_t AwesomePlayer::resume() {
+    LOGI("resume");
+    Mutex::Autolock autoLock(mLock);
+
+    if (mSuspensionState == NULL) {
+        return INVALID_OPERATION;
+    }
+
+    SuspensionState *state = mSuspensionState;
+    mSuspensionState = NULL;
+
+    status_t err;
+    if (state->mFileSource != NULL) {
+        err = setDataSource_l(state->mFileSource);
+
+        if (err == OK) {
+            mFileSource = state->mFileSource;
+        }
+    } else {
+        err = setDataSource_l(state->mUri, &state->mUriHeaders);
+    }
+
+    if (err != OK) {
+        delete state;
+        state = NULL;
+
+        return err;
+    }
+
+    seekTo_l(state->mPositionUs);
+
+    mFlags = state->mFlags & LOOPING;
+
+    if (state->mFlags & PLAYING) {
+        play_l();
+    }
+
+    delete state;
+    state = NULL;
+
+    return OK;
+}
+
 }  // namespace android