MediaRecorder 流程
本文已初始化流程和setAudioSource方法流程为示例,来描述MediaRecorder的工作流程。
一、初始化流程
步骤1、加载jni库,初始化native
该部分代码是静态代码,执行时间在构造方法之前,首先是加载动态库,然后JNI中拿JAVA层的类名和类属性ID为后续JNI访问和操作JAVA做准备,该部分代码不是操作对象,因为构造函数还没有执行到。涉及的类包括:
(1) base\media\java\android\media\MediaRecorder.java
(2) base\media\jni\android_meiia_MediaRecorder.cpp
1.1 加载动态库
static {
System.loadLibrary("media_jni");
native_init();
}
1.2 native_init
// 该部分代码是静态代码,JNI获取类的属性ID,JNI层以静态的形式存储这些属性ID
//
--------wuchunyuan
// This function gets some field IDs, which in turn causes class initialization.
// It is called from a static block in MediaRecorder, which won't run until the
// first time an instance of this class is used.
static void
android_media_MediaRecorder_native_init(JNIEnv *env)
{
jclass clazz;
clazz = env->FindClass("android/media/MediaRecorder");
if (clazz == NULL) {
return;
}
//此处context存放的是mNativeContext的ID,实际mNativeContext赋值在native_setup中,
//context用于存放mediaRecorder.cpp文件中的MediaRecorde类的对象
//env->SetLongField(thiz, fields.context, (jlong)recorder.get());
//JAVA层的MediaRecorder有native层MediaRecorder的指针的值,通过该值C++可以转换回C++中的MediaRecorder对象
--------wuchunyuan
fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
if (fields.context == NULL) {
return;
}
fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");
if (fields.surface == NULL) {
return;
}
jclass surface = env->FindClass("android/view/Surface");
if (surface == NULL) {
return;
}
fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
"(Ljava/lang/Object;IIILjava/lang/Object;)V");
if (fields.post_event == NULL) {
return;
}
clazz = env->FindClass("java/util/ArrayList");
if (clazz == NULL) {
return;
}
gArrayListFields.add = env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z");
gArrayListFields.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
}
- 关联知识a:JNI调用JAVA中的方法
Java_com_kgdwbb_jnistudy_MainActivity_callJavaHelloWorld2(JNIEnv* env, jobject thiz) {
jclass clazz=env->GetObjectClass(thiz);
if(clazz==NULL) return;
jmethodID helloWorld2_methodID=env->GetMethodID(clazz,"helloWorld2","(java/lang/String;)V");
if(helloWorld2_methodID==NULL) return;
const char *msg="hello world";
jstring jmsg=env->NewStringUTF(msg);
//JNI调用JAVA中的方法,此时是通过反射调用,java中的方法并不需要加native关键字
--------wuchunyuan
env->CallVoidMethod(thiz,helloWorld2_methodID,jmsg);
}
- 关联知识b: JNI给JAVA属性赋值
env->SetLongField(thiz, fields.context, (jlong)recorder.get());
步骤2、创建MediaRecorder对象
该部分将创建Java层和Native层MediaRecorder对象,且建立与MediaRecorderClient的进程通信。涉及的类包括:
(1) base\media\java\android\media\MediaRecorder.java
(2) base\media\jni\android_meiia_MediaRecorder.cpp
2.1 创建JAVA层MediaRecorder
//创建JAVA层MediaRecorder对象,并将弱引用传递给native_setup
/**
* Default constructor.
*/
public MediaRecorder() {
Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else {
mEventHandler = null;
}
mChannelCount = 1;
String packageName = ActivityThread.currentPackageName();
// 这里将JAVA层MediaRecorder对象的弱引用传递给NATIVE层,
// 主要用于NATIVE层回调信息给JAVA层
--------wuchunyuan
/* Native setup requires a weak reference to our object.
* It's easier to create it here than in C++.
*/
native_setup(new WeakReference<MediaRecorder>(this), packageName,
ActivityThread.currentOpPackageName());
}
JAVA MediaRecorder向JNI传递弱的引用用于native回调,比如native调用JAVA静态方法postEventFromNative,方法中带了具体的JAVA对象的弱引用,明确了由哪个对象处理。
//c++
//mObject: JAVA层传递给JNI的MediaRecorder 弱引用
//postEventFromNative: JAVA中的静态方法的方法名
void JNIMediaRecorderListener::notify(int msg, int ext1, int ext2)
{
ALOGV("JNIMediaRecorderListener::notify");
JNIEnv *env = AndroidRuntime::getJNIEnv();
env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, NULL);
}
//JAVA
/**
* Called from native code when an interesting event happens. This method
* just uses the EventHandler system to post the event back to the main app thread.
* We use a weak reference to the original MediaRecorder object so that the native
* code is safe from the object disappearing from underneath it. (This is
* the cookie passed to native_setup().)
*/
private static void postEventFromNative(Object mediarecorder_ref,
int what, int arg1, int arg2, Object obj)
{
MediaRecorder mr = (MediaRecorder)((WeakReference)mediarecorder_ref).get();
if (mr == null) {
return;
}
if (mr.mEventHandler != null) {
Message m = mr.mEventHandler.obtainMessage(what, arg1, arg2, obj);
mr.mEventHandler.sendMessage(m);
}
}
2.2 native_setup
static void
android_media_MediaRecorder_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
jstring packageName, jstring opPackageName)
{
ALOGV("setup");
ScopedUtfChars opPackageNameStr(env, opPackageName);
//创建C++的MediaRecorder对象 --------wuchunyuan
sp<MediaRecorder> mr = new MediaRecorder(String16(opPackageNameStr.c_str()));
if (mr == NULL) {
jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
return;
}
if (mr->initCheck() != NO_ERROR) {
jniThrowException(env, "java/lang/RuntimeException", "Unable to initialize media recorder");
return;
}
// create new listener and give it to MediaRecorder
sp<JNIMediaRecorderListener> listener = new JNIMediaRecorderListener(env, thiz, weak_this);
mr->setListener(listener);
// Convert client name jstring to String16
const char16_t *rawClientName = reinterpret_cast<const char16_t*>(
env->GetStringChars(packageName, NULL));
jsize rawClientNameLen = env->GetStringLength(packageName);
String16 clientName(rawClientName, rawClientNameLen);
env->ReleaseStringChars(packageName,
reinterpret_cast<const jchar*>(rawClientName));
// pass client package name for permissions tracking
mr->setClientName(clientName);
setMediaRecorder(env, thiz, mr);
}
static sp<MediaRecorder> setMediaRecorder(JNIEnv* env, jobject thiz, const sp<MediaRecorder>& recorder)
{
Mutex::Autolock l(sLock);
sp<MediaRecorder> old = (MediaRecorder*)env->GetLongField(thiz, fields.context);
if (recorder.get()) {
recorder->incStrong(thiz);
}
if (old != 0) {
old->decStrong(thiz);
}
//将native层的MediaRecorder对象的指针数值保存在JAVA层的MediaRecorder中
env->SetLongField(thiz, fields.context, (jlong)recorder.get());
return old;
}
-
关联知识a: C++类型转换
static_cast ,reinterpret_cast的用法和区别
步骤3、C++ 层MediaRecorder对象创建具体流程
介绍C++ 层MediaRecorder类的创建
#include <media/mediarecorder.h>
sp<MediaRecorder> mr = new MediaRecorder(String16(opPackageNameStr.c_str()));
BpBinder没有重载queryLocalInterface,BnBinder重载queryLocalInterface,返回this
//实现asInterface函数
android::sp<ICameraClient> ICameraClient::asInterface(
const android::sp<android::IBinder>& obj)
{
android::sp<ICameraClient> intr;
if (obj != NULL) {
intr = static_cast<ICameraClient*>(
//queryLocalInterface是在IBinder中定义的,默认返回NULL,但在BBinder的子类BnInterface中,重载了该方法,返回this,而BpBinder没有重载,使用IBinder的默认实现,返回NULL
obj->queryLocalInterface(
ICameraClient::descriptor).get());
if (intr == NULL) {
//构建INTERFACE的Bp端代理对象
intr = new BpCameraClient(obj);
}
}
return intr;
}