記得剛學Android開發(fā)的時候在2011年,那個時候除了hello world,第一個接觸的組件就是這個,這也是目前Android手機運用到最多的組件,有人說沒怎么使用過,目前的各類播放器,短視頻,都屬于多媒體播放,作為Android的多媒體開始鼻祖當屬MediaPlayer了。
回顧下官方的API接口
以官方貼圖為切入點,API地址

從上圖開始我們每一次播放的時候都要按照這樣的狀態(tài)去執(zhí)行,這就是一個典型的狀態(tài)機。
reset->Idle這個狀態(tài)就是起始狀態(tài),可以繼續(xù)執(zhí)行也可以隨時終止->release->End,也可以繼續(xù)執(zhí)行,我們俗稱Idle為起始態(tài)也可以稱之為空閑態(tài),它是伴隨播放器創(chuàng)建后首先走到的地方。若是需要播放,就要先執(zhí)行將播放需要的路徑傳進來setDataSorece,目前這個setDataSorece的重載擴展了很多。這里繼續(xù)溫故下重載(overload),重載的基本原則:
- 被重載的方法必須改變參數(shù)列表;
- 被重載的方法可以改變返回類型;
- 被重載的方法可以改變訪問修飾符;
- 被重載的方法可以聲明新的或更廣的檢查異常;
- 方法能夠在同一個類中或者在一個子類中被重載
那么如果返回類型不一樣算是重載嗎?答案是:不是的
setDataSorece
下面常用方法中,列出不同重載后的方法。這時播放器接收到媒體資源后準備進入初始狀態(tài)。這里需要注意的是,這個順序不能改變,setDataSourece一定是播放器處于空閑態(tài)的時候調(diào)用的,否則就會出錯。具體我們用代碼來分析:
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)用會拋出IllegalStateException異常,剩下兩個是在重載的時候拋出的。至于上面的異常,官方給出注釋了
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
看下底層的代碼是如何實現(xiàn)的,路徑:framework/av/media/mediaplayer.cpp
看起重載后的其中一個方法:
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;
}
這里關注幾個點就可以
需要獲取mediaplayer的服務也就是getMediaPlayerService,這里就要來到經(jīng)常提起的binder機制了,其實就是一個典型的CS模型
- Server端
BnMediaPlayerService 為MediaPlayerService在server端的具體實現(xiàn); - Client端
BpMediaPlayerService為MediaPlayerService在client端的具體代理;
通過BpMediaPlayerService,可以享用MediaPlayerService所提供的服務
通過BpMediaPlayerService可以獲取到IMediaRecorder、IMediaMetadataRetriever、IMediaPlayer、IOMX在client端的代理類BpXXX(IMediaRecorder、IMediaMetadataRetriever、IMediaPlayer、IOMX,這些皆是Bp和Bn的共同接口,和MediaPlayerService一樣,都有Bp和Bn構成)
引用鏈接
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");
//防止重復調(diào)用,它的作用域到函數(shù)結束
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