1、MediaPlayer.java
位于/frameworks/base/media/java/android/media目录,主要是对底层media player的封装,主要的方法如seek、pause、play等也都有对应的jni方法。在MediaPlayer类加载时,调用了native_init()方法。该方法主要是jni层的初始化,将jni层的一些变量和java层的一些方法、变量对应起来。在创建MediaPlayer对象时,调用了native_setup()方法。该方法将java层对象和jni层的对象一一对应起来,并绑定jni层的事件回调对象。
2、com_android_MediaPlayer.cpp
位于/frameworks/base/media/jni目录。起到一个承上启下的作用,相当于java层MediaPlayer和native层MediaPlayer之间的桥梁。有几个重要的jni方法和结构体:
// jni层的初始化
android_media_MediaPlayer_native_init(JNIEnv *env)
{
jclass clazz;
clazz = env->FindClass("android/media/MediaPlayer"); // 获取java MediaPlayer类对象
if (clazz == NULL) {
return;
}
// 获取java MediaPlayer的字段指针,用于保存native MediaPlayer的对象指针。通过该指针,
// 所有的java MediaPlayer对象的native方法,都调用到了native MediaPlayer对象的对应方法
fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
if (fields.context == NULL) {
return;
}
// java MediaPlayer的事件回调方法
fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
"(Ljava/lang/Object;IIILjava/lang/Object;)V");
if (fields.post_event == NULL) {
return;
}
// 和mNativeContext类似,将native SurfaceTexture对象指针保存在java对象的一个字段中
fields.surface_texture = env->GetFieldID(clazz, "mNativeSurfaceTexture", "I");
if (fields.surface_texture == NULL) {
return;
}
}
// java层native_setup(weak reference)的实现,thiz是java层MediaPlayer,weak_this则是java层MediaPlayer的weak reference。
static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
ALOGV("native_setup");
// 创建native media player,即BnMediaPlayer对象。MediaPlayer继承与BnMediaPlayer
sp<MediaPlayer> mp = new MediaPlayer();
if (mp == NULL) {
jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
return;
}
// create new listener and give it to MediaPlayer
// 使用java层MediaPlayer对象和其弱引用,创建一个事件回调listener对象
sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
mp->setListener(listener); // 给MediaPlayer设置MediaPlayerListener事件回调
// Stow our new C++ MediaPlayer in an opaque field in the Java object.
// 将native MediaPlayer对象指针存入java MediaPlayer的一个字段中
setMediaPlayer(env, thiz, mp);
}
// thiz参数是一个java层MediaPlayer对象,而weak_thiz参数则是这个java对象的weak reference
JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
{
// Hold onto the MediaPlayer class for use in calling the static method
// that posts events to the application thread.
jclass clazz = env->GetObjectClass(thiz); // 获取java MediaPlayer的类对象
if (clazz == NULL) {
ALOGE("Can't find android/media/MediaPlayer");
jniThrowException(env, "java/lang/Exception", NULL);
return;
}
mClass = (jclass)env->NewGlobalRef(clazz); // 保存java MediaPlayer的类对象
// We use a weak reference so the MediaPlayer object can be garbage collected.
// The reference is only used as a proxy for callbacks.
mObject = env->NewGlobalRef(weak_thiz); // 保存java MediaPlayer的弱引用
}
JNIMediaPlayerListener::~JNIMediaPlayerListener()
{
// remove global references
JNIEnv *env = AndroidRuntime::getJNIEnv();
env->DeleteGlobalRef(mObject);
env->DeleteGlobalRef(mClass);
}
// native层事件通知到java层
void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)
{
JNIEnv *env = AndroidRuntime::getJNIEnv();
if (obj && obj->dataSize() > 0) {
jobject jParcel = createJavaParcelObject(env);
if (jParcel != NULL) {
Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
nativeParcel->setData(obj->data(), obj->dataSize());
env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
msg, ext1, ext2, jParcel);
}
} else {
env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
msg, ext1, ext2, NULL);
}
if (env->ExceptionCheck()) {
ALOGW("An exception occurred while notifying an event.");
LOGW_EX(env);
env->ExceptionClear();
}
}
static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
{
Mutex::Autolock l(sLock);
// 从java MediaPlayer对象的字段中,获取native MediaPlayer的对象指针
MediaPlayer* const p = (MediaPlayer*)env->GetIntField(thiz, fields.context);
return sp<MediaPlayer>(p);
}
static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
{
Mutex::Autolock l(sLock);
sp<MediaPlayer> old = (MediaPlayer*)env->GetIntField(thiz, fields.context);
if (player.get()) {
player->incStrong(thiz);
}
if (old != 0) {
old->decStrong(thiz);
}
// 将native MediaPlayer的对象指针保存到java MediaPlayer对象的字段中
env->SetIntField(thiz, fields.context, (int)player.get());
return old;
}
// 对应java MediaPlayer的seekTo(int msec)接口,其它接口pause、start等,调用流程和该接口类似
static void
android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, int msec)
{
// 从java MediaPlayer对象中获取native MediaPlayer对象的指针
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return;
}
ALOGV("seekTo: %d(msec)", msec);
// 调用native MediaPlayer的seekTo()
process_media_player_call( env, thiz, mp->seekTo(msec), NULL, NULL );
}
// 处理native MediaPlayer对象的接口返回值
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);
}
}
}
}
3、mediaplayer.h和mediaplayer.cpp
位于/frameworks/av/include/media和/frameworks/av/media/libmedia目录。MediaPlayer继承与BnMediaPlayerClient和IMediaDeathNotifier,并声明了prepare、start、pause、stop、seekTo等多媒体播放相关的控制方法。
class IMediaPlayerClient: public IInterface
{
public:
// 声明构造、析构、asInterface()、getInterfaceDescriptor()方法和descriptor变量
DECLARE_META_INTERFACE(MediaPlayerClient);
// 事件回调接口
virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) = 0;
};
// ----------------------------------------------------------------------------
class BnMediaPlayerClient: public BnInterface<IMediaPlayerClient>
{
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
};
BnMediaPlayerClient在/frameworks/av/include/media/IMediaPlayerClient.h中定义。一眼看完,没有任何新鲜的玩意。
关于DECLARE_META_INTERFACE,可以参考native binder相关类,简单来说就是声明了几个方法和变量。
IMediaDeathNotifier则定义了一个重要方法getMediaPlayerService()。该方法就是获得一个BpMediaPlayerService对象。
// establish binder interface to MediaPlayerService
/*static*/const sp<IMediaPlayerService>&
IMediaDeathNotifier::getMediaPlayerService()
{
ALOGV("getMediaPlayerService");
Mutex::Autolock _l(sServiceLock);
if (sMediaPlayerService == 0) {
// 获取到一个BpServiceManager对象,在[native binder相关类](http://blog.csdn.net/mountains2001/article/details/51494203)一文中我们已经分析过
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
// 通过BpServiceManager获取到BpMediaPlayerService,在[media server分析](http://blog.csdn.net/mountains2001/article/details/51541753)一文中我们已经分析过MediaPlayerService是如何注册到ServiceManager的
binder = sm->getService(String16("media.player"));
if (binder != 0) {
break;
}
ALOGW("Media player service not published, waiting...");
usleep(500000); // 0.5 s
} while (true);
if (sDeathNotifier == NULL) {
sDeathNotifier = new DeathNotifier();
}
binder->linkToDeath(sDeathNotifier);
sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
}
ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");
return sMediaPlayerService; // 保存BpMediaPlayerService对象
}
// binder对象销毁时,需要通知到对侧,避免内存泄露
void IMediaDeathNotifier::DeathNotifier::binderDied(const wp<IBinder>& who) {
ALOGW("media server died");
// Need to do this with the lock held
SortedVector< wp<IMediaDeathNotifier> > list;
{
Mutex::Autolock _l(sServiceLock);
sMediaPlayerService.clear();
list = sObitRecipients;
}
// Notify application when media server dies.
// Don't hold the static lock during callback in case app
// makes a call that needs the lock.
size_t count = list.size();
for (size_t iter = 0; iter < count; ++iter) {
sp<IMediaDeathNotifier> notifier = list[iter].promote();
if (notifier != 0) {
notifier->died();
}
}
}
以下分析MediaPlayer的setDataSource()方法。
status_t MediaPlayer::setDataSource(
const char *url, const KeyedVector<String8, String8> *headers)
{
ALOGV("setDataSource(%s)", url);
status_t err = BAD_VALUE;
if (url != NULL) {
// IMediaDeathNotifier.cpp中定义了getMediaPlayerService(),获取到BpMediaPlayerService对象
const sp<IMediaPlayerService>& service(getMediaPlayerService());
if (service != 0) {
// 使用BnMediaPlayerClient(this)对象创建一个BpMediaPlayer对象。此处的player实际上是一个BpMediaPlayer,player内部包含一个BnMediaPlayerClient对象。而在media player service端则保存这一个BnMediaPlayer对象,而这个BnMediaPlayer内部保存这一个BpMediaPlayerClient对象。应用层的start、pause等命令通过BpMediaPlayer的对应接口调用到服务端的BnMediaPlayer,服务端的BnMediaPlayer的状态、错误等信息则通过BpMediaPlayerClient的notify()方法最终回调到应用层。
sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
// 调用BpMediaPlayer的setDataSource()方法
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(url, headers))) {
player.clear();
}
// 将BpMediaPlayer对象保存下来,初始化MediaPlayer状态,并销毁上一次创建的BpMediaPlayer信息
err = attachNewPlayer(player);
}
}
return err;
}
以下是BnMediaPlayerClient的notify()接口的实现,
void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
{
ALOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
bool send = true;
bool locked = false;
// TODO: In the future, we might be on the same thread if the app is
// running in the same process as the media server. In that case,
// this will deadlock.
//
// The threadId hack below works around this for the care of prepare
// and seekTo within the same process.
// FIXME: Remember, this is a hack, it's not even a hack that is applied
// consistently for all use-cases, this needs to be revisited.
if (mLockThreadId != getThreadId()) {
mLock.lock();
locked = true;
}
// 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;
}
switch (msg) {
case MEDIA_NOP: // interface test message
break;
case MEDIA_PREPARED:
ALOGV("prepared");
// 。。。。省略
break;
case MEDIA_PLAYBACK_COMPLETE:
ALOGV("playback complete");
// 。。。。省略
break;
// 。。。省略
case MEDIA_BUFFERING_UPDATE:
ALOGV("buffering %d", ext1);
break;
case MEDIA_SET_VIDEO_SIZE:
ALOGV("New video size %d x %d", ext1, ext2);
mVideoWidth = ext1;
mVideoHeight = ext2;
break;
case MEDIA_TIMED_TEXT:
ALOGV("Received timed text message");
break;
default:
ALOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
break;
}
// 还记得在jni层创建MediaPlayer时,创建完成后立即又创建了一个JNIMediaPlayerListener对象,并将这个对象设置给了MediaPlayer对象。这里的mListener就是一个JNIMediaPlayerListener对象。
sp<MediaPlayerListener> listener = mListener;
if (locked) mLock.unlock();
// this prevents re-entrant calls into client code
if ((listener != 0) && send) {
Mutex::Autolock _l(mNotifyLock);
ALOGV("callback application");
// 事件通知到JNIMediaPlayerListener
listener->notify(msg, ext1, ext2, obj);
ALOGV("back from callback");
}
结论:java层的MediaPlayer的命令,通过JNI到达mediaplayer.cpp中的MediaPlayer。此处的MediaPlayer实际上是和native层通讯的中间桥梁,是一个BpMediaPlayer和BnMediaPlayerClient的组合体。在创建BpMediaPlayer时,先调用了defaultServiceManager()获取一个BpServiceManager,在从BpServiceManager中获取到BpMediaPlayerService,然后通过IMediaPlayerService的create(pid, BnMediaPlayerClient, session_id)接口,最终得到了一个BpMediaPlayer对象。而它自身又实现了BnMediaPlayerClient接口。这样,java层命令通过BpMediaPlayer传递到ServiceManager一侧的BnMediaPlayer;而底层BnMediaPlayer的状态,又通过ServiceManager一侧的BpMediaPlayerClient,回调到了mediaplayer.cpp中的MediaPlayer的notify()接口,最终经过JNI,回调到上层。
3、MediaPlayerService.h / MediaPlayerService.cpp
位于/av/media/libmediaplayerservice/目录,实现了IMediaPlayService.h接口,继承与BnMediaPlayerService类(在/av/include/media/IMediaPlayerService.h中定义)。
首先,来分析BnMediaPlayer的创建过程:
sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const
sp<IMediaPlayerClient>& client,// BpMediaPlayerClient,实际就是mediaplayer.cpp中的MediaPlayer
int audioSessionId)
{
int32_t connId = android_atomic_inc(&mNextConnId);
// 创建一个BpMediaPlayerClient的封装
sp<Client> c = new Client(
this, pid, connId, client, audioSessionId,
IPCThreadState::self()->getCallingUid());
ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
IPCThreadState::self()->getCallingUid());
wp<Client> w = c;
{
Mutex::Autolock lock(mLock);
mClients.add(w); // 保存client
}
return c;
}
// Client的构造方法,内部保存了BnMediaPlayerService、BpMediaPlayerClient等对象,还保存
// 了PID、UID、session id之类的数据
MediaPlayerService::Client::Client(
const sp<MediaPlayerService>& service, pid_t pid,
int32_t connId, const sp<IMediaPlayerClient>& client,
int audioSessionId, uid_t uid)
{
ALOGV("Client(%d) constructor", connId);
mPid = pid;
mConnId = connId;
mService = service;
mClient = client;
mLoop = false;
mStatus = NO_INIT;
mAudioSessionId = audioSessionId;
mUID = uid;
mRetransmitEndpointValid = false;
#if CALLBACK_ANTAGONIZER
ALOGD("create Antagonizer");
mAntagonizer = new Antagonizer(notify, this);
#endif
}
这个Client是个什么东东?原来它继承与BnMediaPlayer,真相大白了。java层的MediaPlayer的接口,最终调用到了这里。
class Client : public BnMediaPlayer {
// IMediaPlayer interface
virtual void disconnect();
virtual status_t setVideoSurfaceTexture(
const sp<ISurfaceTexture>& surfaceTexture);
virtual status_t prepareAsync();
virtual status_t start();
virtual status_t stop();
virtual status_t pause();
// 。。。省略
}
再看Client的setDataSource()接口:
status_t MediaPlayerService::Client::setDataSource(
const char *url, const KeyedVector<String8, String8> *headers)
{
//ALOGV("setDataSource(%s)", url);
if (url == NULL)
return UNKNOWN_ERROR;
// 检查url,判断是否需要网络权限
if ((strncmp(url, "http://", 7) == 0) ||
(strncmp(url, "https://", 8) == 0) ||
(strncmp(url, "rtsp://", 7) == 0)) {
if (!checkPermission("android.permission.INTERNET")) {
return PERMISSION_DENIED;
}
}
// 使用content provider打开
if (strncmp(url, "content://", 10) == 0) {
// get a filedescriptor for the content Uri and
// pass it to the setDataSource(fd) method
String16 url16(url);
int fd = android::openContentProviderFile(url16);
if (fd < 0)
{
ALOGE("Couldn't open fd for %s", url);
return UNKNOWN_ERROR;
}
setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
close(fd);
return mStatus;
} else {
// 使用url判断初player type
player_type playerType = getPlayerType(url);
// 使用player type创建不同类型的MediaPlayerBase
sp<MediaPlayerBase> p = setDataSource_pre(playerType);
if (p == NULL) {
return NO_INIT;
}
// 调用MediaPlayerBase的setDataSource()接口
setDataSource_post(p, p->setDataSource(url, headers));
return mStatus;
}
}
static player_type getDefaultPlayerType() {
char value[PROPERTY_VALUE_MAX];
if (check_prop_enable("media.amsuperplayer.enable"))
return AMSUPER_PLAYER;
if (property_get("media.stagefright.use-nuplayer", value, NULL)
&& (!strcmp("1", value) || !strcasecmp("true", value))) {
return NU_PLAYER;
}
return STAGEFRIGHT_PLAYER;
}
player_type getPlayerType(const char* url)
{
if (TestPlayerStub::canBeUsed(url)) {
return TEST_PLAYER;
}
/* mp3 using STAGEFRIGHT_PLAYER default */
if (strlen(url) >= 4 && !strcasecmp(".mp3", &url[strlen(url) - 4])) {
LOGV("Create HiPlayer STAGEFRIGHT_PLAYER");
return STAGEFRIGHT_PLAYER;
}
if (!check_prop_enable("media.amsuperplayer.enable")) {
if (!strncasecmp("http://", url, 7)
|| !strncasecmp("https://", url, 8)) {
size_t len = strlen(url);
if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
return NU_PLAYER;
}
if (strstr(url,"m3u8")) {
return NU_PLAYER;
}
}
if (!strncasecmp("rtsp://", url, 7)) {
return NU_PLAYER;
}
}
return getDefaultPlayerType();
}
static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,
notify_callback_f notifyFunc)
{
sp<MediaPlayerBase> p;
switch (playerType) {
case SONIVOX_PLAYER:
ALOGV(" create MidiFile");
p = new MidiFile();
break;
case STAGEFRIGHT_PLAYER:
ALOGV(" create StagefrightPlayer");
p = new StagefrightPlayer;
break;
case NU_PLAYER:
ALOGV(" create NuPlayer");
p = new NuPlayerDriver;
break;
// 。。。。省略
default:
ALOGE("Unknown player type: %d", playerType);
return NULL;
}
if (p != NULL) {
if (p->initCheck() == NO_ERROR) {
p->setNotifyCallback(cookie, notifyFunc);
} else {
p.clear();
}
}
if (p == NULL) {
ALOGE("Failed to create player object");
}
return p;
}
注意:部分厂家会对这一部分代码改动,以接入自己的播放器实现。但是基本流程是固定的,就是根据不同的url,返回不同的MediaPlayerBase对象。
4、MediaPlayerInterface.h
位于目录/av/include/media/。定义了MediaPlayerBase接口,以及上边创建MediaPlayerBase时使用的几个player type的常量。
// 定义了player type常量
enum player_type {
PV_PLAYER = 1,
SONIVOX_PLAYER = 2,
STAGEFRIGHT_PLAYER = 3,
NU_PLAYER = 4,
// Test players are available only in the 'test' and 'eng' builds.
// The shared library with the test player is passed passed as an
// argument to the 'test:' url in the setDataSource call.
TEST_PLAYER = 5,
AAH_RX_PLAYER = 100,
AAH_TX_PLAYER = 101,
AMLOGIC_PLAYER = 110,
AMSUPER_PLAYER = 111,
};
// 定义了回调方法
typedef void (*notify_callback_f)(void* cookie,
int msg, int ext1, int ext2, const Parcel *obj);
// 。。。省略,MediaPlayerBase接口和上层的MediaPlayer接口基本类似
5、StagefrightPlayer.h和StagefrightPlayer.cpp
位于/av/media/libmediaplayerservice/目录下。
StagefrightPlayer::StagefrightPlayer()
: mPlayer(new AwesomePlayer) {
ALOGV("StagefrightPlayer");
mPlayer->setListener(this);
}
StagefrightPlayer::~StagefrightPlayer() {
ALOGV("~StagefrightPlayer");
reset();
delete mPlayer;
mPlayer = NULL;
}
// 。。。。省略
status_t StagefrightPlayer::setDataSource(
const char *url, const KeyedVector<String8, String8> *headers) {
return mPlayer->setDataSource(url, headers);
}
status_t StagefrightPlayer::start() {
ALOGV("start");
return mPlayer->play();
}
// 。。。。省略
从上边的代码看,StagefrightPlayer只是AwesomePlayer的简单封装,不在做分析。
6、AwesomePlayer