記得剛學(xué)Android開(kāi)發(fā)的時(shí)候在2011年敦锌,那個(gè)時(shí)候除了hello world馒疹,第一個(gè)接觸的組件就是這個(gè),這也是目前Android手機(jī)運(yùn)用到最多的組件乙墙,有人說(shuō)沒(méi)怎么使用過(guò)颖变,目前的各類(lèi)播放器,短視頻听想,都屬于多媒體播放腥刹,作為Android的多媒體開(kāi)始鼻祖當(dāng)屬M(fèi)ediaPlayer了。
回顧下官方的API接口
以官方貼圖為切入點(diǎn)汉买,API地址
從上圖開(kāi)始我們每一次播放的時(shí)候都要按照這樣的狀態(tài)去執(zhí)行衔峰,這就是一個(gè)典型的狀態(tài)機(jī)。
reset->Idle這個(gè)狀態(tài)就是起始狀態(tài)蛙粘,可以繼續(xù)執(zhí)行也可以隨時(shí)終止->release->End垫卤,也可以繼續(xù)執(zhí)行,我們俗稱(chēng)Idle為起始態(tài)也可以稱(chēng)之為空閑態(tài)出牧,它是伴隨播放器創(chuàng)建后首先走到的地方穴肘。若是需要播放,就要先執(zhí)行將播放需要的路徑傳進(jìn)來(lái)setDataSorece舔痕,目前這個(gè)setDataSorece的重載擴(kuò)展了很多评抚。這里繼續(xù)溫故下重載(overload),重載的基本原則:
- 被重載的方法必須改變參數(shù)列表赵讯;
- 被重載的方法可以改變返回類(lèi)型盈咳;
- 被重載的方法可以改變?cè)L問(wèn)修飾符耿眉;
- 被重載的方法可以聲明新的或更廣的檢查異常边翼;
- 方法能夠在同一個(gè)類(lèi)中或者在一個(gè)子類(lèi)中被重載
那么如果返回類(lèi)型不一樣算是重載嗎?答案是:不是的
setDataSorece
下面常用方法中鸣剪,列出不同重載后的方法组底。這時(shí)播放器接收到媒體資源后準(zhǔn)備進(jìn)入初始狀態(tài)。這里需要注意的是筐骇,這個(gè)順序不能改變债鸡,setDataSourece一定是播放器處于空閑態(tài)的時(shí)候調(diào)用的,否則就會(huì)出錯(cuò)铛纬。具體我們用代碼來(lái)分析:
public void setDataSource(FileDescriptor fd, long offset, long length)
throws IOException, IllegalArgumentException, IllegalStateException {
try (ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(fd)) {
if (modernFd == null) {
_setDataSource(fd, offset, length);
} else {
_setDataSource(modernFd.getFileDescriptor(), offset, length);
}
} catch (IOException e) {
Log.w(TAG, "Ignoring IO error while setting data source", e);
}
}
非Idle調(diào)用會(huì)拋出IllegalStateException異常厌均,剩下兩個(gè)是在重載的時(shí)候拋出的。至于上面的異常告唆,官方給出注釋了
Sets the data source (MediaDataSource) to use.
Params:
dataSource – the MediaDataSource for the media you want to play
Throws:
IllegalStateException – if it is called in an invalid state
IllegalArgumentException – if dataSource is not a valid MediaDataSource
看下底層的代碼是如何實(shí)現(xiàn)的棺弊,路徑:framework/av/media/mediaplayer.cpp
看起重載后的其中一個(gè)方法:
status_t MediaPlayer::setDataSource(const sp<IDataSource> &source)
{
ALOGV("setDataSource(IDataSource)");
status_t err = UNKNOWN_ERROR;
const sp<IMediaPlayerService> service(getMediaPlayerService());
if (service != 0) {
sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mOpPackageName));
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(source))) {
player.clear();
}
err = attachNewPlayer(player);
}
return err;
}
這里關(guān)注幾個(gè)點(diǎn)就可以
需要獲取mediaplayer的服務(wù)也就是getMediaPlayerService晶密,這里就要來(lái)到經(jīng)常提起的binder機(jī)制了,其實(shí)就是一個(gè)典型的CS模型
- Server端
BnMediaPlayerService 為MediaPlayerService在server端的具體實(shí)現(xiàn)模她; - Client端
BpMediaPlayerService為MediaPlayerService在client端的具體代理稻艰;
通過(guò)BpMediaPlayerService,可以享用MediaPlayerService所提供的服務(wù)
通過(guò)BpMediaPlayerService可以獲取到IMediaRecorder侈净、IMediaMetadataRetriever尊勿、IMediaPlayer、IOMX在client端的代理類(lèi)BpXXX(IMediaRecorder畜侦、IMediaMetadataRetriever元扔、IMediaPlayer、IOMX旋膳,這些皆是Bp和Bn的共同接口摇展,和MediaPlayerService一樣,都有Bp和Bn構(gòu)成)
引用鏈接
status_t MediaPlayer::setDataSource(
const sp<IMediaHTTPService> &httpService,
const char *url, const KeyedVector<String8, String8> *headers)
{
ALOGV("setDataSource(%s)", url);
status_t err = BAD_VALUE;
if (url != NULL) {
const sp<IMediaPlayerService> service(getMediaPlayerService());
if (service != 0) {
sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mOpPackageName));
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(httpService, url, headers))) {
player.clear();
}
err = attachNewPlayer(player);
}
}
return err;
}
status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
{
ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
status_t err = UNKNOWN_ERROR;
const sp<IMediaPlayerService> service(getMediaPlayerService());
if (service != 0) {
sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mOpPackageName));
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(fd, offset, length))) {
player.clear();
}
err = attachNewPlayer(player);
}
return err;
}
status_t MediaPlayer::setDataSource(const sp<IDataSource> &source)
{
ALOGV("setDataSource(IDataSource)");
status_t err = UNKNOWN_ERROR;
const sp<IMediaPlayerService> service(getMediaPlayerService());
if (service != 0) {
sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mOpPackageName));
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(source))) {
player.clear();
}
err = attachNewPlayer(player);
}
return err;
}
prepareAsync
status_t MediaPlayer::prepareAsync()
{
ALOGV("prepareAsync");
//防止重復(fù)調(diào)用溺忧,它的作用域到函數(shù)結(jié)束
Mutex::Autolock _l(mLock);
return prepareAsync_l();
}
// must call with lock held
status_t MediaPlayer::prepareAsync_l()
{
if ( (mPlayer != 0) && ( mCurrentState & (MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
if (mAudioAttributesParcel != NULL) {
mPlayer->setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, *mAudioAttributesParcel);
} else {
mPlayer->setAudioStreamType(mStreamType);
}
mCurrentState = MEDIA_PLAYER_PREPARING;
return mPlayer->prepareAsync();
}
ALOGE("prepareAsync called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
return INVALID_OPERATION;
}
- prepare
- start
- pause
- stop
- reset
- seekTo
- release
- setDisplay
- setSurface
- setVolume
- getTrackInfo
- selectTrack