我是靠谱客的博主 凶狠冬天,最近开发中收集的这篇文章主要介绍Android10.0Auidio之MediaPlayer(四)总结,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

前言
之前说了MediaPlayer如何从java层到jni,以及jin如何callback回调到java,今天继续看看native层的mediaplayer又做了什么。

正文
先说下路径位于frameworks/av/media/libmedia/mediaplayer.cpp,我们先从mediaplayer的构造跟析构函数说起

MediaPlayer::MediaPlayer()
{
    ALOGV("constructor");
    mListener = NULL;
    mCookie = NULL;
    mStreamType = AUDIO_STREAM_MUSIC;
    mAudioAttributesParcel = NULL;
    mCurrentPosition = -1;
    mCurrentSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
    mSeekPosition = -1;
    mSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
    mCurrentState = MEDIA_PLAYER_IDLE;
    mPrepareSync = false;
    mPrepareStatus = NO_ERROR;
    mLoop = false;
    mLeftVolume = mRightVolume = 1.0;
    mVideoWidth = mVideoHeight = 0;
    mLockThreadId = 0;
    mAudioSessionId = (audio_session_t) AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
    AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
    mSendLevel = 0;
    mRetransmitEndpointValid = false;
}

MediaPlayer::~MediaPlayer()
{
    ALOGV("destructor");
    if (mAudioAttributesParcel != NULL) {
        delete mAudioAttributesParcel;
        mAudioAttributesParcel = NULL;
    }
    AudioSystem::releaseAudioSessionId(mAudioSessionId, -1);
    disconnect();
    IPCThreadState::self()->flushCommands();
}

构造函数初始化了好多参数,等具体使用的时候我们再一一细说,析构呢有一个disconnect(),这是做什么的呢

void MediaPlayer::disconnect()
{
    ALOGV("disconnect");
    sp<IMediaPlayer> p;
    {
        Mutex::Autolock _l(mLock);
        p = mPlayer;
        mPlayer.clear();
    }

    if (p != 0) {
        p->disconnect();
    }
}

mPlayer是啥呢?源码先放在这,后续分析,从mediaplayer的构造函数,我们大体知道貌似初始化了好多参数,但不清楚具体都做了什么。我们记得之前我们在分析jni的时候有个 mp->setListener(listener);这个listener是一个jni的JNIMediaPlayerListener,我们回到jni在看下,原来

JNIMediaPlayerListener: public MediaPlayerListener

继承自MediaPlayerListener,通过jni的头文件#include <media/mediaplayer.h>头文件我们发现MediaPlayerListener定义在mediaplayer.h中,而且mediaplayer中构造函数中mListener就是这个listener

status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
{
    ALOGV("setListener");
    Mutex::Autolock _l(mLock);
    mListener = listener;
    return NO_ERROR;
}

到此native层如何回调到java层的逻辑就彻底清楚了。java层在创建MediaPlayer的时候,native层同时也会对应创建一个native的medaplayer,并在jni中set一个mediaplayerListener下来,这个listener主要作用回调jave层的postEventFromNative方法最终实现整个cllback的逻辑,具体可参照Android10.0Auidio之MediaPlayer(二)和Android10.0Auidio之MediaPlayer (三)
继续分析,在看下setDataSource吧,由于setDataSource的函数很多,这里只说一个

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));
        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
            (NO_ERROR != player->setDataSource(fd, offset, length))) {
            player.clear();
        }
        err = attachNewPlayer(player);
    }
    return err;
}

这里先来分析下const sp service(getMediaPlayerService());其实大概也可以猜到获取mediaplayer的service嘛,但是具体怎么实现的呢?
我们知道mediaplayer继承自IMediaDeathNotifier,

IMediaDeathNotifier::getMediaPlayerService()
{
    ALOGV("getMediaPlayerService");
    Mutex::Autolock _l(sServiceLock);
    if (sMediaPlayerService == 0) {
        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder;
        do {
            binder = sm->getService(String16("media.player"));
            if (binder != 0) {
                break;
            }
            ALOGW("Media player service not published, waiting...");
            usleep(500000); // 0.5 s
        } while (true);

        if (sDeathNotifier == NULL) {
            sDeathNotifier = new DeathNotifier();
        }
        binder->linkToDeath(sDeathNotifier);
        sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
    }
    ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");
    return sMediaPlayerService;
}

简单扫一眼,等说到mediaPlayerService的时候在具体说这块,这里不多说了,大概明白是个binder通信就可以了,拿到了service后先执行了sp player(service->create(this, mAudioSessionId));
很简单主要是拿这个服务的binder对象,然后调用service中的setDataSource(),然后attachNewPlayer(player),最终将结果返给jni,最终回调到java层。
这里先简单说下attachNewPlayer函数

status_t MediaPlayer::attachNewPlayer(const sp<IMediaPlayer>& player)
{
    status_t err = UNKNOWN_ERROR;
    sp<IMediaPlayer> p;
    { // scope for the lock
        Mutex::Autolock _l(mLock);

        if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) ||
                (mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) {
            ALOGE("attachNewPlayer called in state %d", mCurrentState);
            return INVALID_OPERATION;
        }

        clear_l();
        p = mPlayer;
        mPlayer = player;
        if (player != 0) {
            mCurrentState = MEDIA_PLAYER_INITIALIZED;
            err = NO_ERROR;
        } else {
            ALOGE("Unable to create media player");
        }
    }

    if (p != 0) {
        p->disconnect();
    }

    return err;
}

代码不是很复杂,基本就是在client端与service端通信,主要通过这个mPlayer。

总结

今天说的好多都是把前边的串联起来了,native层的mediaplayer构造的时候初始化了mListener主要用作向java层传递callback用,而native层的mediaplayer最终通过binder与mediaPlayerService通信,其实这里有一个参数mAudioSessionId我们在setDataSource和构造函数中都看到了,这里没有具体说抽时间单独聊一下这个,因为不仅mediaplayer,包括audiotrack以及audiopolicy很多地方都用到了mAudioSessionId这个东西。我觉得还是有必要单独细说一下的。

最后

以上就是凶狠冬天为你收集整理的Android10.0Auidio之MediaPlayer(四)总结的全部内容,希望文章能够帮你解决Android10.0Auidio之MediaPlayer(四)总结所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(41)

评论列表共有 0 条评论

立即
投稿
返回
顶部