(1) setOnCompletionListener(): 应用程序注册回调对象
[MediaPlayer.java]
----------------------------------------------------------------------------------
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空间。