在Android中,为了更好的支持音频、视频等媒体的播放并提供统一的接口,Android引入了媒体播放服务(Media Player Service)的概念。在整个媒体播放框架中采用的仍然是C/S架构,在本节中将着重介绍原生层的媒体播放。下图显示了媒体播放的类图。

媒体播放类图
其中IMediaPlayerService为封装起来的媒体播放服务接口,BnMediaPlayerService为IMediaPlayerService的本地对象,BpMediaPlayerService为远程IMediaPlayerService对象在本地进程中的代理。在Froyo中,目前能够提供的播放媒体类型为PV_PLAYER(PVPlayer)、SONIVOX_PLAYER(MidiFile)、VORBIS_PLAYER(VorbisPlayer)、STAGEFRIGHT_PLAYER(StagefrightPlayer)等。
下图所示为原生服务部分的状态切换关系。

原生服务状态切换关系
IMediaPlayerClient为封装起来的媒体播放客户端接口,BnMediaPlayerClient为IMediaPlayerClient的本地对象,BpMediaPlayerClient为远程IMediaPlayerClient对象在本地进程中的代理。
IMediaPlayer 为封装起来的本地媒体播放客户端接口,BnMediaPlayer为IMediaPlayer的本地对象,BpMediaPlayer为远程IMediaPlayer对象在本地进程中的代理。
为了使上层代码能够利用媒体播放服务,需要向服务管理器注册媒体播放服务,媒体播放服务的注册过程为:
void MediaPlayerService::instantiate()
{
defaultServiceManager()->addService(String16("media.player"), new MediaPlayerService());
}
获取媒体播放服务的实现如下:
代码:MediaPlayer::getMediaPlayerService()的实现
const sp< IMediaPlayerService>& MediaPlayer::getMediaPlayerService()
{
Mutex::Autolock _l(sServiceLock);
if (sMediaPlayerService.get()==0) {
sp< IServiceManager> sm=defaultServiceManager();//服务管理器
sp< IBinder> binder;
do {
binder=sm->getService(String16("media.player"));//获取媒体播放服务
if (binder !=0)
break;
LOGW("MediaPlayerService not published, waiting...");
usleep(500000); // 0.5s
} while(true);
if (sDeathNotifier==NULL) {
sDeathNotifier=new DeathNotifier();//僵死通知器
}
binder->linkToDeath(sDeathNotifier);
sMediaPlayerService=interface_cast< IMediaPlayerService>(binder);
}
LOGE_IF(sMediaPlayerService==0, "no MediaPlayerService!?");
return sMediaPlayerService;
}
媒体服务为Java层提供的Java JNI接口位于android_media_MediaPlayer.cpp文件中。主要的接口包括:setDataSource、_setVideoSurface、prepare、prepareAsync、_start、_stop、getVideoWidth 、getVideoHeight、seekTo、_pause、isPlaying、getCurrentPosition、getDuration、_release、_reset、setAudioStreamType、setAudioStreamType、setLooping 、isLooping、setVolume、getFrameAt、native_invoke、native_setMetadataFilter、native_getMetadata、native_init、native_setup、native_finalize、snoop等。
媒体播放的基本过程如下图所示。

媒体播放的基本过程
流程说明:
在系统启动时,register_android_media_MediaPlayer()将会被调用,完成媒体播放服务在服务管理器上的注册。
当进行媒体播放时,需首先创建一个Java层的MediaPlayer对象。通过System.loadLibrary()方法加载“media_jni”共享库,然后完成原生MediaPlayer对象的初始化工作。在构造Java层的MediaPlayer对象过程中,需要创建一个JNIMediaPlayerListener对象并添加到原生MediaPlayer对象中。
为了进行媒体播放,在创建好MediaPlayer对象后,需要为MediaPlayer对象设定数据源。如果原生服务对象不存在,则创建一个原生服务客户端对象并建立与服务器端对象的联系,原生媒体播放服务将会根据数据源的类型提供相应的播放服务。目前支持的媒体类型包括mid、midi、smf、xmf、imy(iMelody Ringtone Format)、rtttl(Ring Tone Text Transfer Language)、rtx、ota、ogg、oga等。
在建立C/S连接后,如果播放的是视频文件,需要为视频文件设置播放的Surface,同时设置流媒体类型是音乐、来电铃声、提示音还是闹钟等。
在完成基于异步的准备工作后,即可执行媒体播放任务了,通过调用android_media_MediaPlayer_start()原生方法即可进行媒体播放工作。
如果需要进行暂停,需要调用android_media_MediaPlayer_pause()方法;如果需要停止媒体的播放,需要调用android_media_MediaPlayer_stop()原生方法。
除了这些基本的方法外,Android还提供了android_media_MediaPlayer_setVolume原生方法来设置音量;提供了android_media_MediaPlayer_getDuration原生方法来获得已播时间;提供了android_media_MediaPlayer_isPlaying()原生方法来获得播放状态;提供了android_media_MediaPlayer_seekTo()原生方法来设置进度。