前面要作個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,其實就是new了playerFactory實例,並鍵值對一一對應。在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分析.....