android媒体框架之图库行为
建议用用在设备休眠的时候第三方视频播放器主动调用VideoView.suspend()方法
我们很多第三方播放器应用在休眠唤醒的时候处理的不是很棒,造成很多平台不能很好的兼容,最进在公司就处理过此类问题。
默认情况下,当我们点击power键的时候,我们客户端播放器会和服务端断开连接,此时服务端的Client会析构,当再次返回时会重新唤醒时服务端会重新创建服务端,读取上次保存的位置,开始播放或者待用户确认后开始播放,这样做会节约功耗,你不希望用户用你产品后本来可以撑一天的手机,现在只能用半天了吧~
废话少说,直接把图库的行为给大家看下:
SEP 1 .MovieActivity
@Override
public void onPause() {
mPlayer.onPause();
super.onPause();
}
当点击power键的时候,会调用movieActitivy的onPause方法
SEP 2. MoviePlayer
public void onPause() {
mHasPaused = true;
mHandler.removeCallbacksAndMessages(null);
mVideoPosition = mVideoView.getCurrentPosition();
mBookmarker.setBookmark(mUri, mVideoPosition, mVideoView.getDuration());
mVideoView.suspend();
mResumeableTime = System.currentTimeMillis() + RESUMEABLE_TIMEOUT;
}
保存状态,保存为书签,调用VideoView的挂起方法,其真正调用的是VideoView的release方法
SEP 3 .ViewoView
/*
* release the media player in any state
*/
private void release(boolean cleartargetstate) {
if (mMediaPlayer != null) {
mMediaPlayer.reset();
mMediaPlayer.release();
mMediaPlayer = null;
mCurrentState = STATE_IDLE;
if (cleartargetstate) {
mTargetState = STATE_IDLE;
}
}
}
SEP4.MediaPlay.java
public void release() {
stayAwake(false);
updateSurfaceScreenOn();
mOnPreparedListener = null;
mOnBufferingUpdateListener = null;
mOnCompletionListener = null;
mOnSeekCompleteListener = null;
mOnErrorListener = null;
mOnInfoListener = null;
mOnVideoSizeChangedListener = null;
mOnTimedTextListener = null;
_release();
}
private native void _release();
... ...
public void reset() {
stayAwake(false);
_reset();
// make sure none of the listeners get called anymore
mEventHandler.removeCallbacksAndMessages(null);
}
private native void _reset();
先说reset:
SEP5.android_media_MediaPlayer.cpp
// If exception is NULL and opStatus is not OK, this method sends an error
// event to the client application; otherwise, if exception is not NULL and
// opStatus is not OK, this method throws the given exception to the client
// application.
static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message)
{
if (exception == NULL) { // Don't throw exception. Instead, send an event.
if (opStatus != (status_t) OK) {
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0);
}
} else { // Throw exception!
if ( opStatus == (status_t) INVALID_OPERATION ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
} else if ( opStatus == (status_t) PERMISSION_DENIED ) {
jniThrowException(env, "java/lang/SecurityException", NULL);
} else if ( opStatus != (status_t) OK ) {
if (strlen(message) > 230) {
// if the message is too long, don't bother displaying the status code
jniThrowException( env, exception, message);
} else {
char msg[256];
// append the status code to the message
sprintf(msg, "%s: status=0x%X", message, opStatus);
jniThrowException( env, exception, msg);
}
}
}
}
SEP6.MediaPlayer.cpp
void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
{
... ...
// Allows calls from JNI in idle state to notify errors
if (!(msg == MEDIA_ERROR && mCurrentState == MEDIA_PLAYER_IDLE) && mPlayer == 0) {
ALOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
if (locked) mLock.unlock(); // release the lock when done.
return;
}
... ...
}
再回头看,release
SEP7.android_media_MediaPlayer.cpp
static void
android_media_MediaPlayer_release(JNIEnv *env, jobject thiz)
{
ALOGV("release");
decVideoSurfaceRef(env, thiz);
sp<MediaPlayer> mp = setMediaPlayer(env, thiz, 0);
if (mp != NULL) {
// this prevents native callbacks after the object is released
mp->setListener(0);
mp->disconnect();
}
}
SEP8.MediaPlayer.cpp
void MediaPlayer::disconnect()
{
ALOGV("disconnect");
sp<IMediaPlayer> p;
{
Mutex::Autolock _l(mLock);
p = mPlayer;
mPlayer.clear();
}
if (p != 0) {
p->disconnect();
}
}
这里的IMediaPlayer的指针指向的就是MdiaPlayerService::Client;智能指针clear就会调用其析构函数,然后断开与服务端的连接
SEP9.MediaPlayerService.cpp
MediaPlayerService::Client::~Client()
{
ALOGV("Client(%d) destructor pid = %d", mConnId, mPid);
mAudioOutput.clear();
wp<Client> client(this);
disconnect();
mService->removeClient(client);
}
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);
p = 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();
}
disconnectNativeWindow();
IPCThreadState::self()->flushCommands();
}
关闭和服务端的连接流程基本就是这样的。返回流程后续补上。

浙公网安备 33010602011771号