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,其实就是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分析.....