记得刚学Android开发的时候在2011年,那个时候除了hello world,第一个接触的组件就是这个,这也是目前Android手机运用到最多的组件,有人说没怎么使用过,目前的各类播放器,短视频,都属于多媒体播放,作为Android的多媒体开始鼻祖当属MediaPlayer了。
回顾下官方的API接口
以官方贴图为切入点,API地址
从上图开始我们每一次播放的时候都要按照这样的状态去执行,这就是一个典型的状态机。
reset->Idle这个状态就是起始状态,可以继续执行也可以随时终止->release->End,也可以继续执行,我们俗称Idle为起始态也可以称之为空闲态,它是伴随播放器创建后首先走到的地方。若是需要播放,就要先执行将播放需要的路径传进来setDataSorece,目前这个setDataSorece的重载扩展了很多。这里继续温故下重载(overload),重载的基本原则:
- 被重载的方法必须改变参数列表;
- 被重载的方法可以改变返回类型;
- 被重载的方法可以改变访问修饰符;
- 被重载的方法可以声明新的或更广的检查异常;
- 方法能够在同一个类中或者在一个子类中被重载
那么如果返回类型不一样算是重载吗?答案是:不是的
setDataSorece
下面常用方法中,列出不同重载后的方法。这时播放器接收到媒体资源后准备进入初始状态。这里需要注意的是,这个顺序不能改变,setDataSourece一定是播放器处于空闲态的时候调用的,否则就会出错。具体我们用代码来分析:
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调用会抛出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
看下底层的代码是如何实现的,路径: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,这里就要来到经常提起的binder机制了,其实就是一个典型的CS模型
- Server端
BnMediaPlayerService 为MediaPlayerService在server端的具体实现; - 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");
//防止重复调用,它的作用域到函数结束
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