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分析.....

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章