音频系统跟应用层直接相关的部分
从上层看,跟音频相关的功能概括说就是音频、视频的的录制、回放。与之直接相关的类有MediaPlayer,MediaRecorder。他们具有同时处理音频、视频的能力。
1, MediaPlayer主要处理音视频的回放,它是一个状态机,依赖于MediaPlayerService来完成具体功能,并项应用程序反馈当前的播放情况。
如下是MediaPlayer的状态迁移图,有状态机约束,不能跨状态操作
下面看Mediaplayer的实现,看它是如何完成应用的播放请求的。
以状态从idle到Initialized为例,触发条件是调用setDataSource函数。
从mediaplayer.java开始,经过jni层,android_media_mediaplayer.cpp,到本地层mediaplayer.cpp。
直接看mediaplayer.cpp的代码:
status_t MediaPlayer::setDataSource(const sp<IDataSource> &source)@ mediaplayer.cpp {
//获取mediaplayerservice的服务。
const sp<IMediaPlayerService> service(getMediaPlayerService());
//有Mediaplayerservice,创建一个IMediaPlayer实例,这个实例是mediaplayer和mediaplayerservice之间通信的工具。因为mediaplayer是属于应用进程的,而mediaplayerservice属于meidaserver进程,他们之间的通信是跨进程。
sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
//通过setdatasource把播放源设置进去。
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(source))) {
player.clear();
}
//把这个Imediaplayer实例跟mediaplayer.cpp关联起来,同时把状态从idle转到Initialized。
err = attachNewPlayer(player);
return err;
}
2, MediaRecorder,音视频的录制。
MediaRecorder也同样有严格的状态机约束。
MediaRecorder的状态迁移图,及相关函数。
音视频录制,涉及的硬件设备,主要包括:
视频:通过视频录制设备(camera)采集数据,并将采集到的图像显示在终端屏幕上同步预览,可以将数据与surfaceView建立关联以实现预览,最后保存到指定的存储设备。
音频:通过音频录制设备(如mic)采集数据,然后保存到指定存储设备中。对于音视频都可以调用MediaRecorder的函数配置各种参数。
编码器:将音视频数据存储为文件之前,需要调用编码器做前期处理。
应用程序负责描述需求(通过MediaRecorder提供的设置函数),MediaRecorder根据这些需求在系统整合、协调相关设备,完成需求。
下图是MediaRecorder的框架图:
MediaPlayerService是底层多媒体的代理者,stageFright是系统的多媒体库,在不同的版本中,多媒体库可能会有变化,mediaplayerservice的存在使得多媒体库的改变不会影响到上层框架。
SurfaceView实现视频录制时的预览功能,同时结合opengl可以对视频数据进行效果调整。
下面是一个多媒体录制程序实例,以mediaRecorderTest.java中的实例为参考:
Frameworks/base/media/tests/mediaframeworktest/…/MediaRecorderTest.java
//为了代码清晰,这个方法中函数调用的try-catch异常没加。
public void testPortraitH263() throws Exception {
mRecorder = new MediaRecorder();
//获取一个Camera实例,可以指定camera编号。
mCamera = Camera.open(CAMERA_ID);
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(352, 288);
parameters.set("orientation", "portrait");
mCamera.setParameters(parameters);
//这一步是必不可少的,解锁camera,让另一个进程可以访问他。通常情况下camera是被锁定在拥有活动的camera实例的进程,直到这个进程调用了release,断开并释放相机资源。
但是,为了允许在进程之间快速切换,可以调用unlock方法来释放camera临时的为其他进程使用。
mCamera.unlock();
//将MediaRecorder与camera建立连接,这个设置会传到stagefright,
mRecorder.setCamera(mCamera);
int codec = MediaRecorder.VideoEncoder.H263;
int frameRate = MediaProfileReader.getMaxFrameRateForCodec(codec);
//调用录制video方法,
recordVideo(frameRate, 352, 288, codec,
MediaRecorder.OutputFormat.THREE_GPP,
MediaNames.RECORDED_PORTRAIT_H263, true);
//资源释放
mCamera.lock();
mCamera.release();
videoRecordedResult =
validateVideo(MediaNames.RECORDED_PORTRAIT_H263, 352, 288);
}
private void recordVideo(int frameRate, int width, int height,
int videoFormat, int outFormat, String outFile, boolean videoOnly) {
//设置音视频的来源,
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
//设置文件格式,输出文件名,路径。
mRecorder.setOutputFormat(outFormat);
mRecorder.setOutputFile(outFile);
mRecorder.setVideoFrameRate(frameRate);
mRecorder.setVideoSize(width, height);
//设置音视频的编码器。
mRecorder.setVideoEncoder(videoFormat);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
//设置预览窗口。
mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
mRecorder.prepare();
mRecorder.start();
Thread.sleep(MediaNames.RECORDED_TIME);
mRecorder.stop();
mRecorder.release();
}
系统支持的音视频来源有哪些,以及是否要添加权限,可以参考MediaRecorder.java中的VideoSource,AudioSource这两个子类
MediaRecorder.java{
public final class AudioSource {
/** Default audio source **/
public static final int DEFAULT = 0;
/** Microphone audio source */
public static final int MIC = 1;
/** Voice call uplink (Tx) audio source.
* <p>
* Capturing from <code>VOICE_UPLINK</code> source requires the
* {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT} permission.
* This permission is reserved for use by system components and is not available to
* third-party applications.
* </p>
*/
public static final int VOICE_UPLINK = 2;
/** Voice call downlink (Rx) audio source.
* <p>
* Capturing from <code>VOICE_DOWNLINK</code> source requires the
* {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT} permission.
* This permission is reserved for use by system components and is not available to
* third-party applications.
* </p>
*/
public static final int VOICE_DOWNLINK = 3;
/** Voice call uplink + downlink audio source
* <p>
* Capturing from <code>VOICE_CALL</code> source requires the
* {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT} permission.
* This permission is reserved for use by system components and is not available to
* third-party applications.
* </p>
*/
public static final int VOICE_CALL = 4;
/** Microphone audio source with same orientation as camera if available, the main
* device microphone otherwise */
public static final int CAMCORDER = 5;
/** Microphone audio source tuned for voice recognition if available, behaves like
* {@link #DEFAULT} otherwise. */
public static final int VOICE_RECOGNITION = 6;
}
public final class VideoSource {
public static final int DEFAULT = 0;
/** Camera video source
* <p>
* Using the {@link android.hardware.Camera} API as video source.
* </p>
*/
public static final int CAMERA = 1;
/** Surface video source
* <p>
* Using a Surface as video source.
* </p><p>
* This flag must be used when recording from an
* {@link android.hardware.camera2} API source.
* </p><p>
* When using this video source type, use {@link MediaRecorder#getSurface()}
* to retrieve the surface created by MediaRecorder.
*/
public static final int SURFACE = 2;
}
}
上面是通过MediaRecorder封装的接口,来完成音视频的录制,接着看下mediaRecorder的源码实现。
以前面实例中的一个接口setPreviewDisplay为例:
public void setPreviewDisplay(Surface sv) @MediaRecorder.java{
//这里只是保存了设置的surface对象。
mSurface = sv;
}
Java层保存的surface对象,什么时候用呢?从上面的框架图可知,要完成音视频的录制是通过MediaRecorder.cpp,进而使用库层的服务,所以这里的surface应该在MediaRecorder.cpp被使用。
//在这个jni的初始化函数中,会通过name和类型签名,找到mediaRecorder(java)中mSurface变量,然后保存到fields(fields_t结构体)中。static void android_media_MediaRecorder_native_init(JNIEnv *env)
@ android_media_MediaRecorder.cpp{
clazz = env->FindClass("android/media/MediaRecorder");
fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");
}
static void android_media_MediaRecorder_prepare(JNIEnv *env, jobject thiz)
@ android_media_MediaRecorder.cpp {
//这里得到是mediarecorder(cpp)对象,这个对象是在native_setup中创建的,然后存在了fields的fields.context中。
sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
//先获取java层的对象mSurface,进一步获取native_surface。
jobject surface = env->GetObjectField(thiz, fields.surface);
const sp<Surface> native_surface = get_surface(env, surface);
//调用MediaRecorder.cpp中的setPreviewSurface,最后把surface设置到stageFrightRecorder中。
if (process_media_recorder_call
(env, mr->setPreviewSurface(native_surface->getIGraphicBufferProducer()),
"java/lang/RuntimeException", "setPreviewSurface failed.")) {
return;
}
}
//这里的mMediaRecorder是sp<IMediaRecorder> 类型的对象。前面说过IMediaRecorder是应用程序跟MediaPlayerService之间的桥梁。mMediaRecorder是在mediaRecorder.cpp的构造函数中创建的。
status_t MediaRecorder::setPreviewSurface(const sp<IGraphicBufferProducer>& surface)
@ mediarecorder.cpp {
status_t ret = mMediaRecorder->setPreviewSurface(surface);
}
//通过mediaplayerService创建了mMediaRecorder对象。
MediaRecorder::MediaRecorder(const String16& opPackageName) @mediarecorder.cpp {
const sp<IMediaPlayerService> service(getMediaPlayerService());
mMediaRecorder = service->createMediaRecorder(opPackageName);
//同时把状态置为IDLE,状态机开始运转。
if (mMediaRecorder != NULL) {
mCurrentState = MEDIA_RECORDER_IDLE;
}
}
//看下MediaPlayerService是如何生成mMediaRecorder对象的。
sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(const String16
&opPackageName)@ MediaPlayerService.cpp {
//这里生成是一个MediaRecorderClient对象,并把它加到了mMediaRecorderClients列表中,以做全局管理。所以IMediaRecorder对应的实现类是MediaRecorderClient。应用进程中MediaRecorder向Mediaplayerservice发起的业务请求都是通过MediaRecorderClient。
sp<MediaRecorderClient> recorder = new MediaRecorderClient(this, pid, opPackageName);
wp<MediaRecorderClient> w = recorder;
mMediaRecorderClients.add(w);
return recorder;
}
看下MediaRecorderClient的继承关系:
class MediaRecorderClient : publicBnMediaRecorder…
class BnMediaRecorder: publicBnInterface<IMediaRecorder>…
template<typename INTERFACE>
class BnInterface : public INTERFACE,public BBinder
所以是一个多继承 MediaRecorderClient:publicIMediaRecorder, public BBinder…
一方面具有了IMediaRecorder的功能,另一方面BBinder实现了跨进程的能力。
接着前面MediaRecorder.cpp中对setPreviewSurface的实现,就是调用了mMediaRecorder的中setPreviewSurface函数。
status_t MediaRecorderClient::setPreviewSurface(const sp<IGraphicBufferProducer>& surface)
@ MediaRecorderClient.cpp {
return mRecorder->setPreviewSurface(surface);
}
这里的mRecorder是MediaRecorderBase *mRecorder;类型。
StagefrightRecorder *AVMediaServiceFactory::createStagefrightRecorder(
const String16 &opPackageName) @ AVMediaServiceFactory.cpp {
return new StagefrightRecorder(opPackageName);
}
具体的实现类是StagefrightRecorder,从前面的框架图看出,stagefright是android的多媒体库。