AndroidMediaRecorder架构详解

AndroidMediaRecorder架构详解

2015年03月27日 15:38:54 phoebe_2012 阅读数:5960 标签: android MediaRecorder 架构 C层录音 更多

个人分类: android

AndroidMediaRecorder架构详解

1.     简介

在android中录制音频有两种方式,MediaRecorder和AudioRecord。两者的区别如下:

(1)      MediaRecorder

简单方便,不需要理会中间录制过程,结束录制后可以直接得到音频文件进行播放;录制的音频文件是经过压缩的,需要设置编码器;录制的音频文件可以用系统自带的播放器播放。

(2)      AudioRecorder

在声音录制过程中,可以处理采集的声音数据,如降噪、合成等。过程为一段一段进行录制然后得到数据分别进行处理。录制的是PCM格式的音频文件,需要用AudioTrack来播放,AudioTrack更接近底层。

本文主要详解MediaRecorder架构,从上层调到StagefrightRecorder的流程以及应用层录音接口调用的流程。(注:本次分析基于android4.4.2源码)

 

2.     应用层录音接口调用流程

(1)    调用new MediaRecorder()构造函数得到实例。

(2)    调用setOutputFormat()设定媒体文件的输出格式。

(3)    调用setAudioSource()设定音频的录入源以及调用setAudioEncoder()设定音频的编码方式。

(4)    调用setOutputFile()设定记录的媒体文件保存的路径。

(5)    调用prepare()准备录制。

(6)    调用start()开始录制。

(7)    记录完成后,调用stop()停止录制。

 

3.     应用层调到StagefrightRecorder的流程

如图1所示,MediaRecorder在运行时,可以分成Client和Server两个部分,它们分别在两个进程中运行,它们之间使用Binder机制实现IPC通讯。

 

图1 录音从Java层调到StagefrightRecorder的流程图

 

(1)      手机启动时会启动进程/system/bin/mediaserver。该进程会把media相关服务注册到ServiceManager中,如MediaPlayerService。

(/frameworks/av/media/mediaserver/main_mediaserver.cpp)

 

 
  1. 124 sp<ProcessState> proc(ProcessState::self());

  2. 125 sp<IServiceManager> sm = defaultServiceManager();

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

  4. 127 AudioFlinger::instantiate();

  5. 128 MediaPlayerService::instantiate();

  6. 129 CameraService::instantiate();

  7. 130 AudioPolicyService::instantiate();

  8. 131 registerExtensions();

  9. 132 ProcessState::self()->startThreadPool();

  10. 133 IPCThreadState::self()->joinThreadPool();

 

(/frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp)

 

 
  1. 204<span style="white-space:pre"> </span>void MediaPlayerService::instantiate() {

  2. 205 <span style="white-space:pre"> </span>defaultServiceManager()->addService(

  3. 206 <span style="white-space:pre"> </span>String16("media.player"), new MediaPlayerService());

  4. 207<span style="white-space:pre"> </span>}

 

 

(2)      应用层创建MediaRecorder实例:mMediaRecorder = new MediaRecorder(); 调用SDK中MediaRecorder.java

(frameworks\base\media\java\android\media\MediaRecorder.java)

 

 
  1. 98 public MediaRecorder() {

  2. 99

  3. 100 Looper looper;

  4. 101 if ((looper = Looper.myLooper()) != null) {

  5. 102 mEventHandler = new EventHandler(this, looper);

  6. 103 } else if ((looper = Looper.getMainLooper()) != null) {

  7. 104 mEventHandler = new EventHandler(this, looper);

  8. 105 } else {

  9. 106 mEventHandler = null;

  10. 107 }

  11. 108

  12. 109 String packageName = ActivityThread.currentPackageName();

  13. 110 /* Native setup requires a weak reference to our object.

  14. 111 * It's easier to create it here than in C++.

  15. 112 */

  16. 113 native_setup(new WeakReference<MediaRecorder>(this), packageName);

  17. 114 }

 

 

通过JNI方式调用到framework层android_media_MediaRecorder.cpp。

(\frameworks\base\media\jni\android_media_MediaRecorder.cpp)

 

 
  1. 418static void

  2. 419android_media_MediaRecorder_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,

  3. 420 jstring packageName)

  4. 421{

  5. 422 ALOGV("setup");

  6. 423

  7. 424 sp<MediaRecorder> mr = new MediaRecorder();

  8. 425 if (mr == NULL) {

  9. 426 jniThrowException(env, "java/lang/RuntimeException", "Out of memory");

  10. 427 return;

  11. 428 }

  12. 429 if (mr->initCheck() != NO_ERROR) {

  13. 430 jniThrowException(env, "java/lang/RuntimeException", "Unable to initialize media recorder");

  14. 431 return;

  15. 432 }

  16. 433

  17. 434 // create new listener and give it to MediaRecorder

  18. 435 sp<JNIMediaRecorderListener> listener = new JNIMediaRecorderListener(env, thiz, weak_this);

  19. 436 mr->setListener(listener);

  20. 437

  21. 438 // Convert client name jstring to String16

  22. 439 const char16_t *rawClientName = env->GetStringChars(packageName, NULL);

  23. 440 jsize rawClientNameLen = env->GetStringLength(packageName);

  24. 441 String16 clientName(rawClientName, rawClientNameLen);

  25. 442 env->ReleaseStringChars(packageName, rawClientName);

  26. 443

  27. 444 // pass client package name for permissions tracking

  28. 445 mr->setClientName(clientName);

  29. 446

  30. 447 setMediaRecorder(env, thiz, mr);

  31. 448}

 

(3)      继而调用mediarecorder.cpp的构造函数,它首先会从ServiceManager中获得MediaPlayerService服务,然后通过服务来创建recorder。这个recorder就是录音的真实实例。

 (frameworks\av\media\libmedia\mediarecorder.cpp)

 

 
  1. 617MediaRecorder::MediaRecorder() : mSurfaceMediaSource(NULL)

  2. 618{

  3. 619 ALOGV("constructor");

  4. 620

  5. 621 const sp<IMediaPlayerService>& service(getMediaPlayerService());

  6. 622 if (service != NULL) {

  7. 623 mMediaRecorder = service->createMediaRecorder();

  8. 624 }

  9. 625 if (mMediaRecorder != NULL) {

  10. 626 mCurrentState = MEDIA_RECORDER_IDLE;

  11. 627 }

  12. 628

  13. 629

  14. 630 doCleanUp();

  15. 631}

 

(4)      通过getMediaPlayerService得到的service其实是 BpMediaPlayerService,它和mediaserver进程中的BnMediaPlayerService是相对应的,共同负责进程间 binder通信。BpMediaPlayerService中的createMediaRecorder其实是通过binder机制将 CREATE_MEDIA_RECORDER消息发送出去。

(/frameworks/av/media/libmedia/IMediaPlayerService.cpp)

 

 
  1. 81 virtual sp<IMediaRecorder> createMediaRecorder()

  2. 82 {

  3. 83 Parcel data, reply;

  4. 84 data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());

  5. 85 remote()->transact(CREATE_MEDIA_RECORDER, data, &reply);

  6. 86 return interface_cast<IMediaRecorder>(reply.readStrongBinder());

  7. 87 }

 

(5)      在BnMediaPlayerService中,通过onTransact()来处理接收到的消息, 并返回结果。当接收消息中的code为CREATE_MEDIA_RECORDER时,调用MediaPlayerService 中的createMediaRecorder函数。在该函数中创建了一个MediaRecorderClient的实例,也就是说 MediaPlayerService会为每个client应用进程创建一个相应的MediaRecorderClient的实例,来提供服务。

(/frameworks/av/media/libmedia/IMediaPlayerService.cpp)

 

 
  1. 210status_t BnMediaPlayerService::onTransact(

  2. 211 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)

  3. 212{

  4. 213 switch (code) {

  5. 214 case CREATE: {

  6. 215 CHECK_INTERFACE(IMediaPlayerService, data, reply);

  7. 216 sp<IMediaPlayerClient> client =

  8. 217 interface_cast<IMediaPlayerClient>(data.readStrongBinder());

  9. 218 int audioSessionId = data.readInt32();

  10. 219 sp<IMediaPlayer> player = create(client, audioSessionId);

  11. 220 reply->writeStrongBinder(player->asBinder());

  12. 221 return NO_ERROR;

  13. 222 } break;

 

 
  1. 262 case CREATE_MEDIA_RECORDER: {

  2. 263 CHECK_INTERFACE(IMediaPlayerService, data, reply);

  3. 264 sp<IMediaRecorder> recorder = createMediaRecorder();

  4. 265 reply->writeStrongBinder(recorder->asBinder());

  5. 266 return NO_ERROR;

  6. 267 } break;

 

 
  1. 337 default:

  2. 338 return BBinder::onTransact(code, data, reply, flags);

  3. 339 }

  4. 340}

(/frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp)

 

231sp<IMediaRecorder> MediaPlayerService::createMediaRecorder()232{233 pid_t pid = IPCThreadState::self()->getCallingPid();234 sp<MediaRecorderClient> recorder = new MediaRecorderClient(this, pid);235 wp<MediaRecorderClient> w = recorder;236 Mutex::Autolock lock(mLock);237 mMediaRecorderClients.add(w);238 ALOGV("Create new media recorder client from pid %d", pid);239 return recorder;240}

 

(6)      如此MediaRecorder.cpp就得到了一个recorder的实例,对它来说这个实例和本 地的其他类的实例没什么用法上的区别,但其实这个实例是运行在另外一个进程中。实现这种假象的就是binder机制。在 MediaRecorderClient的构造函数中,才会真正的创建StagefrightRecorder的具体实例,即真正的录制对象,使用的 StageFright多媒体框架。在android 4.0以后只有StagefrightRecorder一个录制框架。在2.2、2.3中还存在另外一个录制对象PVMediaRecorder,使用的 是OpenCore框架实现录音或录像。

(/frameworks/av/media/libmediaplayerservice/MediaRecorderClient.cpp)

 

 
  1. 303MediaRecorderClient::MediaRecorderClient(const sp<MediaPlayerService>& service, pid_t pid)

  2. 304{

  3. 305 ALOGV("Client constructor");

  4. 306 mPid = pid;

  5. 307 mRecorder = new StagefrightRecorder;

  6. 308 mMediaPlayerService = service;

  7. 309}


图2是录音创建实例的时序图

 

 

图2 录音创建实例的时序图

 

4.     Application Framework层与libraries层录音函数对应关系

mMediaRecorder = new MediaRecorder();

mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);

mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);

mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);

mMediaRecorder.setOutputFile(recordFile.getAbsolutePath());

mMediaRecorder.prepare(); 

mMediaRecorder.start();

mMediaRecorder.stop();

mMediaRecorder.release();

 

sp<MediaRecorder> mr = newMediaRecorder();

mr->setAudioSource(1);  //MIC = 1

mr->setOutputFormat(0); //DEFAULT = 0;

mr->setAudioEncoder(0);//DEFAULT = 0;

mr->setOutputFile(fos.getFD(), 0, 0);

mr->prepare();

mr->start();

mr->stop();

mr->release();

 

5.     总结

通过对androidmediarecorder架构的详解,了解各模块调用的流程,不仅可以实现在应用层调用录音接口进行录音,还能直接调用 libraries层录音接口函数进行C层录音。同时,若需要监控录音,则可以Hook系统进程/system/bin/mediaserver的 ioctl函数,从而拦截该进程的binder通信过程,通过解析binder通信数据包,就可以监控到手机中所有录音软件的录音行为。

 

6.     参考资料

[1]      Android录音MediaRecorder/AudioRecorder相关总结:

http://www.360doc.com/content/12/0919/19/10764837_237084032.shtml

[2]      MediaRecorder和AudioRecord的区别和联系:

http://blog.csdn.net/ameyume/article/details/7885744

[3]      MediaRecorder类介绍:http://blog.csdn.net/mark_dev/article/details/7249415

[4]      AndroidXRef:http://androidxref.com/
---------------------  
作者:phoebe_2012  
来源:CSDN  
原文:https://blog.csdn.net/phoebe_2012/article/details/44677725  
版权声明:本文为博主原创文章,转载请附上博文链接!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值