frameworks/base/media/java/android/media/MediaPlayer.java
/**
* Resets the MediaPlayer to its uninitialized state. After calling
* this method, you will have to initialize it again by setting the
* data source and calling prepare().
*/
public void reset() {
mSelectedSubtitleTrackIndex = -1;
synchronized(mOpenSubtitleSources) {
for (final InputStream is: mOpenSubtitleSources) {
try {
is.close();
} catch (IOException e) {
}
}
mOpenSubtitleSources.clear();
}
if (mSubtitleController != null) {
mSubtitleController.reset();
}
if (mTimeProvider != null) {
mTimeProvider.close();
mTimeProvider = null;
}
stayAwake(false);
_reset();
// make sure none of the listeners get called anymore
if (mEventHandler != null) {
mEventHandler.removeCallbacksAndMessages(null);
}
synchronized (mIndexTrackPairs) {
mIndexTrackPairs.clear();
mInbandTrackIndices.clear();
};
resetDrmState();
}
private native void _reset();
主要步驟
- 銷毀 Subtitle相關處理
- 銷毀 mTimeProvider
- stayAwake(false),不保持屏幕長開的的狀態
- _reset(),調用到jni層,下面分析
- 銷毀 mEventHandler所有消息,不再向播放器應用發送任何消息
frameworks/base/media/jni/android_media_MediaPlayer.cpp
static void
android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz)
{
ALOGV("reset");
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return;
}
process_media_player_call( env, thiz, mp->reset(), NULL, NULL );
}
frameworks/av/media/libmedia/mediaplayer.cpp
status_t MediaPlayer::reset_l()
{
mLoop = false;
if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;
mPrepareSync = false;
if (mPlayer != 0) {
status_t ret = mPlayer->reset();
if (ret != NO_ERROR) {
ALOGE("reset() failed with return code (%d)", ret);
mCurrentState = MEDIA_PLAYER_STATE_ERROR;
} else {
mPlayer->disconnect();
mCurrentState = MEDIA_PLAYER_IDLE;
}
// setDataSource has to be called again to create a
// new mediaplayer.
mPlayer = 0;
mCurrentBufferingSettings = BufferingSettings();
return ret;
}
clear_l();
return NO_ERROR;
}
主要步驟:
- 調用MediaPlayerService 的reset方法
這一步主要執行到NuPlayer的reset - 調用MediaPlayerService 的disconnect
這一步會銷毀MediaPlayerService 保存的服務端mediaplayer binder實例mClient
和NuPlayer的實例 - 將mPlayer銷毀
mPlayer是mediaplayer 同服務端MediaPlayerService
frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
status_t MediaPlayerService::Client::reset()
{
ALOGV("[%d] reset", mConnId);
mMaybeVideoAlive = false;
mRetransmitEndpointValid = false;
sp<MediaPlayerBase> p = getPlayer();
if (p == 0) return UNKNOWN_ERROR;
return p->reset();
}
void MediaPlayerService::Client::disconnect()
{
ALOGV("disconnect(%d) from pid %d", mConnId, mPid);
// grab local reference and clear main reference to prevent future
// access to object
sp<MediaPlayerBase> p;
{
Mutex::Autolock l(mLock);
//使用了一個局部變量對mPlayer引用,即對底層播放器的引用。
//會使強引用計數加1。在這個函數退出后,p的生命周期也結束,智能指針會自動銷毀底層播放器實例
p = mPlayer;
//調用了智能指針的clear方法,將強引用計數減1,并m_ptr = 0
//mClient 為sp<IMediaPlayerClient>,即是對mediaplayer的引用
//mPlayer 為sp<MediaPlayerBase>
//mClient和mPlayer為全局的引用變量,使用clear后, mClient和mPlayer將無法再被使用
mClient.clear();
mPlayer.clear();
}
// clear the notification to prevent callbacks to dead client
// and reset the player. We assume the player will serialize
// access to itself if necessary.
if (p != 0) {
p->setNotifyCallback(0, 0);
#if CALLBACK_ANTAGONIZER
ALOGD("kill Antagonizer");
mAntagonizer->kill();
#endif
p->reset();
}
{
Mutex::Autolock l(mLock);
disconnectNativeWindow_l();
}
IPCThreadState::self()->flushCommands();
}
disconnect步驟稍微有點繞。先用一個局部變量p 指向了mPlayer,即增加了對NuPlayer的強引用計數,接著銷毀了全局變量mClient和mPlayer引用。mClient計數應該會為0,所以對應的實例也會被銷毀。而NuPlayer的引用計數由于局部變量p,引用計數不會為0。接著通過p 將NuPlayer的回調函數置為0,并調用到NuPlayer的reset方法,這里是重復調用了reset方法,因為release流程只會調用mediaplayer的disconnect方法,不會調用到reset方法。在函數執行完后,局部變量p會自動銷毀,同時也會自動銷毀NuPlayer實例
主要步驟:
- 銷毀mClient和mPlayer的引用
- 設置NuPlayer的回調函數為0
- 調用NuPlayer reset方法
- disconnectNativeWindow_l(沒詳細研究,應該是涉及到顯示的window,跟surface和wms相關)
- flushCommands() 調用talkWithDriver(false)立即發送mOut緩存中的命令數據