在Android中,為了更好的支持音頻、視頻等媒體的播放并提供統(tǒng)一的接口,Android引入了媒體播放服務(wù)(Media Player Service)的概念。在整個(gè)媒體播放框架中采用的仍然是C/S架構(gòu),在本節(jié)中將著重介紹原生層的媒體播放。下圖顯示了媒體播放的類(lèi)圖。

媒體播放類(lèi)圖
其中IMediaPlayerService為封裝起來(lái)的媒體播放服務(wù)接口,BnMediaPlayerService為IMediaPlayerService的本地對(duì)象,BpMediaPlayerService為遠(yuǎn)程IMediaPlayerService對(duì)象在本地進(jìn)程中的代理。在Froyo中,目前能夠提供的播放媒體類(lèi)型為PV_PLAYER(PVPlayer)、SONIVOX_PLAYER(MidiFile)、VORBIS_PLAYER(VorbisPlayer)、STAGEFRIGHT_PLAYER(StagefrightPlayer)等。
下圖所示為原生服務(wù)部分的狀態(tài)切換關(guān)系。

原生服務(wù)狀態(tài)切換關(guān)系
IMediaPlayerClient為封裝起來(lái)的媒體播放客戶端接口,BnMediaPlayerClient為IMediaPlayerClient的本地對(duì)象,BpMediaPlayerClient為遠(yuǎn)程IMediaPlayerClient對(duì)象在本地進(jìn)程中的代理。
IMediaPlayer 為封裝起來(lái)的本地媒體播放客戶端接口,BnMediaPlayer為IMediaPlayer的本地對(duì)象,BpMediaPlayer為遠(yuǎn)程IMediaPlayer對(duì)象在本地進(jìn)程中的代理。
為了使上層代碼能夠利用媒體播放服務(wù),需要向服務(wù)管理器注冊(cè)媒體播放服務(wù),媒體播放服務(wù)的注冊(cè)過(guò)程為:
void MediaPlayerService::instantiate()
{
defaultServiceManager()->addService(String16("media.player"), new MediaPlayerService());
}
獲取媒體播放服務(wù)的實(shí)現(xiàn)如下:
代碼:MediaPlayer::getMediaPlayerService()的實(shí)現(xiàn)
const sp< IMediaPlayerService>& MediaPlayer::getMediaPlayerService()
{
Mutex::Autolock _l(sServiceLock);
if (sMediaPlayerService.get()==0) {
sp< IServiceManager> sm=defaultServiceManager();//服務(wù)管理器
sp< IBinder> binder;
do {
binder=sm->getService(String16("media.player"));//獲取媒體播放服務(wù)
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;
}
媒體服務(wù)為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等。
媒體播放的基本過(guò)程如下圖所示。

媒體播放的基本過(guò)程
流程說(shuō)明:
在系統(tǒng)啟動(dòng)時(shí),register_android_media_MediaPlayer()將會(huì)被調(diào)用,完成媒體播放服務(wù)在服務(wù)管理器上的注冊(cè)。
當(dāng)進(jìn)行媒體播放時(shí),需首先創(chuàng)建一個(gè)Java層的MediaPlayer對(duì)象。通過(guò)System.loadLibrary()方法加載“media_jni”共享庫(kù),然后完成原生MediaPlayer對(duì)象的初始化工作。在構(gòu)造Java層的MediaPlayer對(duì)象過(guò)程中,需要?jiǎng)?chuàng)建一個(gè)JNIMediaPlayerListener對(duì)象并添加到原生MediaPlayer對(duì)象中。
為了進(jìn)行媒體播放,在創(chuàng)建好MediaPlayer對(duì)象后,需要為MediaPlayer對(duì)象設(shè)定數(shù)據(jù)源。如果原生服務(wù)對(duì)象不存在,則創(chuàng)建一個(gè)原生服務(wù)客戶端對(duì)象并建立與服務(wù)器端對(duì)象的聯(lián)系,原生媒體播放服務(wù)將會(huì)根據(jù)數(shù)據(jù)源的類(lèi)型提供相應(yīng)的播放服務(wù)。目前支持的媒體類(lèi)型包括mid、midi、smf、xmf、imy(iMelody Ringtone Format)、rtttl(Ring Tone Text Transfer Language)、rtx、ota、ogg、oga等。
在建立C/S連接后,如果播放的是視頻文件,需要為視頻文件設(shè)置播放的Surface,同時(shí)設(shè)置流媒體類(lèi)型是音樂(lè)、來(lái)電鈴聲、提示音還是鬧鐘等。
在完成基于異步的準(zhǔn)備工作后,即可執(zhí)行媒體播放任務(wù)了,通過(guò)調(diào)用android_media_MediaPlayer_start()原生方法即可進(jìn)行媒體播放工作。
如果需要進(jìn)行暫停,需要調(diào)用android_media_MediaPlayer_pause()方法;如果需要停止媒體的播放,需要調(diào)用android_media_MediaPlayer_stop()原生方法。
除了這些基本的方法外,Android還提供了android_media_MediaPlayer_setVolume原生方法來(lái)設(shè)置音量;提供了android_media_MediaPlayer_getDuration原生方法來(lái)獲得已播時(shí)間;提供了android_media_MediaPlayer_isPlaying()原生方法來(lái)獲得播放狀態(tài);提供了android_media_MediaPlayer_seekTo()原生方法來(lái)設(shè)置進(jìn)度。