(1) setOnCompletionListener(): 應用程序註冊回調對象java
[MediaPlayer.java]android
----------------------------------------------------------------------------------
public interface OnCompletionListener
{
void onCompletion(MediaPlayer mp);
}
public void setOnCompletionListener(OnCompletionListener listener)
{
mOnCompletionListener = listener;
}
private OnCompletionListener mOnCompletionListener;
----------------------------------------------------------------------------------
應用程序調用setOnCompletionListener()註冊回調對象,該對象的onCompletion()方法在MediaPlayer.EventHandler.handleMessage()中被調用。
----------------------------------------------------------------------------------
case MEDIA_PLAYBACK_COMPLETE:
if (mOnCompletionListener != null)
mOnCompletionListener.onCompletion(mMediaPlayer);
return;
----------------------------------------------------------------------------------
(2) postEventFromNative(): 傳遞來自Native的事件
[MediaPlayer.java]
----------------------------------------------------------------------------------
private static void postEventFromNative(Object mediaplayer_ref,
int what, int arg1, int arg2, Object obj)
{
MediaPlayer mp = (MediaPlayer)((WeakReference)
mediaplayer_ref).get();
if (mp == null) {
return;
}
if (mp.mEventHandler != null) {
Message m = mp.mEventHandler.obtainMessage(what, arg1,
arg2, obj);
mp.mEventHandler.sendMessage(m);
}
}
----------------------------------------------------------------------------------
postEventFromNative()是在哪裏被調用的呢?應該是Native世界。
(3) env->CallStaticVoidMethod(): 調用postEventFromNative()
[android_media_MediaPlayer.cpp]
I. android_media_MediaPlayer_native_init(): 記錄"postEventFromNative()"方法的ID
-----------------------------------------------------------------------------------
android_media_MediaPlayer_native_init(JNIEnv *env)
{
clazz = env->FindClass("android/media/MediaPlayer");
fields.post_event = env->GetStaticMethodID(clazz,
"postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)
V");
}
-----------------------------------------------------------------------------------
該native方法在MediaPlayer.java類第一次被加載時調用。
-----------------------------------------------------------------------------------
[MediaPlayer.java]
public class MediaPlayer
{
... ...
static {
System.loadLibrary("media_jni");
native_init();
}
... ...
}
-----------------------------------------------------------------------------------
II. android_media_MediaPlayer_native_setup(): 建立Native中的MediaPlayer客戶端
該native方法在構造MediaPlayer.java對象時被調用,
-----------------------------------------------------------------------------------
[MediaPlayer.java]
public class MediaPlayer
{
... ...
public MediaPlayer() {
... ...
native_setup(new WeakReference<MediaPlayer>(this));
}
... ...
}
-----------------------------------------------------------------------------------
該方法建立Native的MediaPlayer,
-----------------------------------------------------------------------------------
static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz,
jobject weak_this)
{
sp<MediaPlayer> mp = new MediaPlayer();
sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener
(env, thiz, weak_this);
mp->setListener(listener);
setMediaPlayer(env, thiz, mp);
}
-----------------------------------------------------------------------------------
也就是說MediaPlayer.java構造時,建立了一個Native的MediaPlayer,
該MediaPlayer繼承BnMediaPlayerClient,因此可稱爲 --- 提供Binder服
務的MediaPlayer客戶端。也就是說,它自己是MediaPlayer客戶端,同
時它也提供Binder服務,估計目的就是使MediaPlayer服務端能回調客戶
端的方法。簡稱Native中的MediaPlayer客戶端。
該方法同時設置了listener,該listener的notify()方法會調用
postEventFromNative()。
-----------------------------------------------------------------------------------
void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const
Parcel *obj)
{
JNIEnv *env = AndroidRuntime::getJNIEnv();
env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
msg, ext1, ext2, NULL);
}
-----------------------------------------------------------------------------------
III. MediaPlayer::notify(): Native中的MediaPlayer客戶端notify()方法
-----------------------------------------------------------------------------------
void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
{
... ...
mListener->notify(msg, ext1, ext2, obj);
}
-----------------------------------------------------------------------------------
因此MediaPlayer::notify()什麼時候被調用?
應該是被BpMediaPlayerClient調用,怎麼找到它?
IV. MediaPlayer::setDataSource():傳出Native中MediaPlayer客戶端的代理
-----------------------------------------------------------------------------------
status_t MediaPlayer::setDataSource(
const char *url, const KeyedVector<String8, String8> *headers)
{
const sp<IMediaPlayerService>& service(getMediaPlayerService());
if (service != 0) {
sp<IMediaPlayer> player(service->create(getpid(), this,
mAudioSessionId));
if (NO_ERROR != player->setDataSource(url, headers)) {
player.clear();
}
err = attachNewPlayer(player);
}
return err;
}
-----------------------------------------------------------------------------------
這裏取得IMediaPlayer的代理端,同時也把IMediaPlayerClient的服務端即BnMediaPlayerClient傳遞出去。
總結一:
MediaPlayer.java對象構造時,建立Native中的MediaPlayer客戶端。
setDataSource()方法會取得IMediaPlayer代理端。來自IMediaPlayer的回調經過BpMediaPlayerClient調用到Java空間。
V. BpMediaPlayerClient.notify()被調用
BnMediaPlayerClient經過上面的service->create()傳遞,該create最後調用(經過binder),
-----------------------------------------------------------------------------------
sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const
sp<IMediaPlayerClient>& client,
int audioSessionId)
{
sp<Client> c = new Client(
this, pid, connId, client, audioSessionId,
IPCThreadState::self()->getCallingUid());
... ...
return c;
}
-----------------------------------------------------------------------------------
Client的構造函數,記錄client到mClient中。client的notify()方法被MediaPlayerService::Client::notify()調用。
VI. setDataSource() 最終建立MeidaPlayerBase
-----------------------------------------------------------------------------------
sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer
(player_type playerType)
{
sp<MediaPlayerBase> p = mPlayer;
if (p == NULL) {
p = android::createPlayer(playerType, this, notify);
}
return p;
}
static sp<MediaPlayerBase> createPlayer(player_type playerType, void*
cookie,
notify_callback_f notifyFunc)
{
sp<MediaPlayerBase> p;
switch (playerType) {
case STAGEFRIGHT_PLAYER:
LOGV(" create StagefrightPlayer");
p = new StagefrightPlayer;
break;
case NU_PLAYER:
LOGV(" create NuPlayer");
p = new NuPlayerDriver;
break;
default:
LOGE("Unknown player type: %d", playerType);
return NULL;
}
if (p != NULL) {
if (p->initCheck() == NO_ERROR) {
p->setNotifyCallback(cookie, notifyFunc);
} else {
p.clear();
}
}
return p;
}
-----------------------------------------------------------------------------------
VII. StagefrightPlayer->setNotifyCallback()
記錄notifyFunc到mNotify中
VIII. StageFrightPlayer->sendEvent()
最終連鎖觸發到postEventFromNative()
[base\media\libstagefright\awesomePlayer.cpp]
void AwesomePlayer::onStreamDone() {
... ...
notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
}
void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
if (mListener != NULL) {
sp<MediaPlayerBase> listener = mListener.promote();
if (listener != NULL) {
listener->sendEvent(msg, ext1, ext2);
}
}
}
這樣整個舊貫通了。
再總結:
1) MediaPlayer.java對象構造,建立Native中的MediaPlayer客戶端;
setDataSource()方法會取得IMediaPlayer代理端, 即建立了IMediaPlayer的服務端,進而建立如StageFrightPlayer。
回調經過StageFrightPlayer引用BpMediaPlayerClient送給BnMediaPlayerClient,即Native中的MediaPlayer客戶端,而後調回java空間。
惋惜圖片發不了!cookie