Android 原生播放器MediaPlayer

记得刚学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 &source)
{
    ALOGV("setDataSource(IDataSource)");
    status_t err = UNKNOWN_ERROR;
    const sp service(getMediaPlayerService());
    if (service != 0) {
        sp 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 &httpService,
        const char *url, const KeyedVector *headers)
{
    ALOGV("setDataSource(%s)", url);
    status_t err = BAD_VALUE;
    if (url != NULL) {
        const sp service(getMediaPlayerService());
        if (service != 0) {
            sp 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 service(getMediaPlayerService());
    if (service != 0) {
        sp 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 &source)
{
    ALOGV("setDataSource(IDataSource)");
    status_t err = UNKNOWN_ERROR;
    const sp service(getMediaPlayerService());
    if (service != 0) {
        sp 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

你可能感兴趣的:(Android 原生播放器MediaPlayer)