android7.1 audio研究- mediaplayer

    前面要作个audioflinger方面的培训,为了更好的理解audio流程,结合以前搞linux媒体框架时的理解。以全志A64平台机器为样本,从上到下梳理了下audio部份,包括: audiosystem 、 audiotrack 、codeclib(编解码库 libstagefright  cedarX)、 audioflinger 、 hal 、tinyalsa 与asla驱动。一直想写个完整audio部份分析,但是目前还没写完,现从mediaplayer native(c++)部份开始。

先从调用一个mediaplyer播放native music的播放用例开始。用例很简单就是调用mediaplayer接口来播放一个本地文件。

Android.mk:

LOCAL_PATH := $(call my-dir)

 

include $(CLEAR_VARS)

 

LOCAL_C_INCLUDES := \

    frameworks/av/include/

LOCAL_SRC_FILES := test.cpp 

 

LOCAL_SHARED_LIBRARIES := \

               libcutils \

               libutils \

               libbinder \

     libmedia \

               liblog

               

 

LOCAL_MODULE := mediaplayer_test

include $(BUILD_EXECUTABLE)

test.cpp:

#include <stdio.h>

#include <assert.h>

#include <limits.h>

#include <unistd.h>

#include <fcntl.h>

#include <string.h>

#include <binder/Parcel.h>

#include <binder/IPCThreadState.h>

#include <binder/IServiceManager.h>

 

#include <media/mediaplayer.h>

#include <media/MediaPlayerInterface.h>

 

#include "utils/Log.h"

 

#define TEST_FILE_PATH "/data/audio/test.mp3"

 

using namespace android;

 

#define USE_PREPARE_ASYNC

 

Condition mPlayerCond;

Mutex mLock;

 

class audioPlayerListener : public MediaPlayerListener

{

public:

              audioPlayerListener()

              {}

              virtual ~audioPlayerListener()

              {}

              void notify(int msg, int ext1, int ext2, const Parcel *obj)

              {

                            ALOGD("notify msg: %d", msg);

                            switch (msg)

                            {

              #ifdef USE_PREPARE_ASYNC

                            case MEDIA_PREPARED:

                                          mPlayerCond.signal();

                                          break;

              #endif

                            case MEDIA_PLAYBACK_COMPLETE:

                                          mPlayerCond.signal();

                                          break;

                            default:

                                          break;

                            }

              }

};

 

int main(int argc, char **argv)

{

              char file_path[128] = {0};

 

              strcpy(file_path, TEST_FILE_PATH);

              if (argc > 1)

                            strcpy(file_path, (char *)(argv[1]));

              ALOGD("file: %s", file_path);

 

    int fd = open(file_path, O_RDONLY);

              if(fd < 0)

              {

                            ALOGD("error! open test file fail!");

                            return -1;

              }

 

              android::ProcessState::self()->startThreadPool(); //becareful, for issue cannot call BnMediaPlayerClient notify

             

              sp<MediaPlayer> mMP = new MediaPlayer();

    mMP->setDataSource(fd, 0, 0x7fffffffL);

              //mMP->setAudioStreamType(AUDIO_STREAM_MUSIC);

 

              sp<audioPlayerListener> pListen = new audioPlayerListener();

              mMP->setListener(pListen);

              //mMP->setLooping(0);

              //mMP->setVolume(1.0, 1.0);

    //mMP->setVideoSurfaceTexture(surface->getSurfaceTexture());

#ifdef USE_PREPARE_ASYNC

              mMP->prepareAsync();

              mLock.lock();

              mPlayerCond.waitRelative(mLock, seconds(10));

              mLock.unlock();

#else

              mMP->prepare();

#endif

              ALOGD("start play!!!");

    mMP->start();

#if 0

    while (mMP->isPlaying())

              {

        ALOGD("++++++++playing...");

        sleep(1);

    }

#else

              mLock.lock();

              //mPOR.waitRelative(mLock, seconds(10));

              mPlayerCond.wait(mLock);

              mLock.unlock();

#endif

              ALOGD("play over!!!");

    //mMP->disconnect();

              mMP->stop();

              mMP->reset();

              mMP.clear();

              //pListen.clear();

    close(fd);

    return 0;

}

使用了mediaplayer,我们再来分析mediaplayer部份代码。

     mediaplayer分为client端与service端,代码分别位于

            frameworks\av\media\libmedia

            frameworks\av\media\libmediaplayerservice

大概框架图如下所示:

             

 

mediaplayerservice作为服务端,在开机的时候由mediaserver.rc脚本启动。

frameworks\av\media\mediaserver\main_mediaserver.cpp

int main(int argc __unused, char **argv __unused)

{

    signal(SIGPIPE, SIG_IGN);

 

    sp<ProcessState> proc(ProcessState::self());

    sp<IServiceManager> sm(defaultServiceManager());

    ALOGI("ServiceManager: %p", sm.get());

    InitializeIcuOrDie();

    MediaPlayerService::instantiate();

    ResourceManagerService::instantiate();

    registerExtensions();

    ProcessState::self()->startThreadPool();

    IPCThreadState::self()->joinThreadPool();

}

 

frameworks\av\media\libmediaplayerservice\mediaplayerservice.cpp

void MediaPlayerService::instantiate() {

    defaultServiceManager()->addService(

            String16("media.player"), new MediaPlayerService());

}

         上面完成向system注册service。

         再看MediaPlayerService::MediaPlayerService()构造函数里面做了哪些操作。

MediaPlayerService::MediaPlayerService()

{

    mNextConnId = 1;

    mBatteryAudio.refCount = 0;

    for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {

        mBatteryAudio.deviceOn[i] = 0;

        mBatteryAudio.lastTime[i] = 0;

        mBatteryAudio.totalTime[i] = 0;

    }

    mBatteryAudio.deviceOn[SPEAKER] = 1;

    BatteryNotifier::getInstance().noteResetVideo();

    MediaPlayerFactory::registerBuiltinFactories();

}

 

MediaPlayerFactory::registerBuiltinFactories()static操作,用来注册平台支持的player,其实就是newplayerFactory实例,并键值对一一对应。在getPlayerType_l()时,只需获取序号就可以得到对应的playerFactory实例。

void MediaPlayerFactory::registerBuiltinFactories() {

    Mutex::Autolock lock_(&sLock);

    if (sInitComplete)

        return;

    registerFactory_l(new AwPlayerFactory(), AW_PLAYER);

    registerFactory_l(new NuPlayerFactory(), NU_PLAYER);

    registerFactory_l(new TestPlayerFactory(), TEST_PLAYER);

    sInitComplete = true;

}

 

可以看到A64支持awplayer,nuplayer与testplayer。

MediaPlayerFactory是用来给厂商适配注册自己的player的统一入口,如果厂商想加上自己的player,需要实现xxxPlayerFactory类,MediaPlayerInterface是抽象出来的player基类,厂商的播放器xxxPlayer必须基于MediaPlayerInterface接口去做。

         class xxxPlayerFactory : public MediaPlayerFactory::IFactory

              {

          virtual sp<MediaPlayerBase> createPlayer(pid_t /* pid */) {

                return new xxxPlayer();

          }

              }

再来分析mediaplayer demo流程。

sp<MediaPlayer> mMP = new MediaPlayer();

mMP->setDataSource(fd, 0, 0x7fffffffL);

在new了mediaplayer client端对象后,setDataSource操作。setDataSource有几种接口,有纯本地fd操作的,也有流媒体协议的,还有纯数据流的。我们以本地文件fd接口入手。

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;

}

可以看到先获取MediaPlayerService的服务代理,调用create(),经IMediaPlayerService  Binder调用到mediaplayerservice的create()

sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,

        audio_session_t audioSessionId)

{

    pid_t pid = IPCThreadState::self()->getCallingPid();

    int32_t connId = android_atomic_inc(&mNextConnId);

 

    sp<Client> c = new Client(

            this, pid, connId, client, audioSessionId,

            IPCThreadState::self()->getCallingUid());

 

    ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,

         IPCThreadState::self()->getCallingUid());

    wp<Client> w = c;

    {

        Mutex::Autolock lock(mLock);

        mClients.add(w);

    }

    return c;

}

在mediaplayerservice端new了一个client(BnMediaplayer)对象,与client端一一对应,用来记录client端。

再执行player->setDataSource(),最终调到

status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)

{

    struct stat sb;

    int ret = fstat(fd, &sb);

    if (ret != 0) {

        ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));

        return UNKNOWN_ERROR;

    }

    if (offset >= sb.st_size) {

        ALOGE("offset error");

        return UNKNOWN_ERROR;

    }

    if (offset + length > sb.st_size) {

        length = sb.st_size - offset;

        ALOGV("calculated length = %lld", (long long)length);

    }

    player_type playerType = MediaPlayerFactory::getPlayerType(this,fd,offset,length);

    sp<MediaPlayerBase> p = setDataSource_pre(playerType);

    if (p == NULL) {

        return NO_INIT;

    }

    // now set data source

    setDataSource_post(p, p->setDataSource(fd, offset, length));

    return mStatus;

}

这里会根据播放文件,按MediaPlayerFactory里面设定的规则取合适的播放器序号。在setDataSource_pre(playerType)里面会new出真正的播放器对象,并new一个AudioOutput输出对象。AudioOutput的作用是用来把解码出来的pcm数据传到AudioTrack播放输出。

sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(player_type playerType)

{

    ALOGV("player type = %d", playerType);

    // create the right type of player

    sp<MediaPlayerBase> p = createPlayer(playerType);

    if (p == NULL) {

        return p;

    }

    sp<IServiceManager> sm = defaultServiceManager();

    sp<IBinder> binder = sm->getService(String16("media.extractor"));

    mExtractorDeathListener = new ServiceDeathNotifier(binder, p, MEDIAEXTRACTOR_PROCESS_DEATH);

    binder->linkToDeath(mExtractorDeathListener);

 

    binder = sm->getService(String16("media.codec"));

    mCodecDeathListener = new ServiceDeathNotifier(binder, p, MEDIACODEC_PROCESS_DEATH);

    binder->linkToDeath(mCodecDeathListener);

 

    if (!p->hardwareOutput()) {

        Mutex::Autolock l(mLock);

        mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(),

                mPid, mAudioAttributes);

        static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);

    }

    return p;

}

 

由上可知,在应用程序执行mMP->setDataSource()时,其实mediaplayerservice就已经帮选择了相应的player,并new了player的实例。

再看mMP->prepareAsync() (mMP->prepare()),这里prepare有2个接口,一个同步,一个异步。mMP->prepare()是同步接口,会一直等到播放器到PREPARED状态才返回,适用于资源比较小的情况(如果是awplayer,这个操作里面会解析整个文件取到 mediainfo,文件大就比较耗时)。mMP->prepareAsync()是异步操作,会立即返回,通过设置的listenner来监听播放器的状态变化。

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;

}

status_t MediaPlayerService::Client::prepareAsync()

{

    ALOGV("[%d] prepareAsync", mConnId);

    sp<MediaPlayerBase> p = getPlayer();

    if (p == 0) return UNKNOWN_ERROR;

    status_t ret = p->prepareAsync();

#if CALLBACK_ANTAGONIZER

    ALOGD("start Antagonizer");

    if (ret == NO_ERROR) mAntagonizer->start();

#endif

    return ret;

}

不管是prepare()还是prepareAsync(),最终都会调到player的prepareAsync()。此处以awplayer来分析,最终调到XPlayerPrepareAsync()(会启动demux组件完成demux解包,完成后会置player的状态为prepared,并将状态notify上报);下面会就awplayer来做具体分析。

 

 

再看mMP->start();

status_t MediaPlayer::start()

{

    status_t ret = NO_ERROR;

    Mutex::Autolock _l(mLock);

    mLockThreadId = getThreadId();

    if (mCurrentState & MEDIA_PLAYER_STARTED) {

        ret = NO_ERROR;

    } else if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |

                    MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {

        mPlayer->setLooping(mLoop);

        mPlayer->setVolume(mLeftVolume, mRightVolume);

        mPlayer->setAuxEffectSendLevel(mSendLevel);

        mCurrentState = MEDIA_PLAYER_STARTED;

        ret = mPlayer->start();

        if (ret != NO_ERROR) {

            mCurrentState = MEDIA_PLAYER_STATE_ERROR;

        } else {

            if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {

                ALOGV("playback completed immediately following start()");

            }

        }

    } else {

        ALOGE("start called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());

        ret = INVALID_OPERATION;

    }

    mLockThreadId = 0;

    return ret;

}

如果当前已经prepare了,则调用player的start(),最终调到xplayer的start()。

status_t MediaPlayerService::Client::start()

{

    ALOGV("[%d] start", mConnId);

    sp<MediaPlayerBase> p = getPlayer();

    if (p == 0) return UNKNOWN_ERROR;

    p->setLooping(mLoop);

    return p->start();

}

下接aw libcedarX与stagefright分析.....

猜你喜欢

转载自blog.csdn.net/wenjin359/article/details/82344699