本章节中静态分析了推测相机拍照音流程,下一章节中在 CameraService 中添加堆栈信息,动态分析拍照音的流程。
文件列表:
- frameworks\base\core\java\android\hardware\Camera.java
- frameworks\base\core\jni\android_hardware_Camera.cpp
- frameworks\av\camera\Camera.cpp
- frameworks\av\services\camera\libcameraservice\api1\CameraClient.cpp
- frameworks\av\services\camera\libcameraservice\CameraService.cpp
APK 中调用
// frameworks\base\core\java\android\hardware\Camera.java
public final boolean disableShutterSound()
{
return _enableShutterSound(/*enabled*/false);
}
// native 相机拍照音方法
private native final boolean _enableShutterSound(boolean enabled);
进入本地方法 android_hardware_Camera.cpp 中的拍照音函数:
// frameworks\base\core\jni\android_hardware_Camera.cpp
static jboolean android_hardware_Camera_enableShutterSound(JNIEnv *env, jobject thiz,
jboolean enabled)
{
ALOGV("enableShutterSound");
sp<Camera> camera = get_native_camera(env, thiz, NULL); // 获取本地相机实例,从类名上定位到 Camera.cpp
if (camera == 0) return JNI_FALSE;
int32_t value = (enabled == JNI_TRUE) ? 1 : 0;
status_t rc = camera->sendCommand(CAMERA_CMD_ENABLE_SHUTTER_SOUND, value, 0); // 发送拍照音命令
if (rc == NO_ERROR) {
return JNI_TRUE;
} else if (rc == PERMISSION_DENIED) {
return JNI_FALSE;
} else {
jniThrowRuntimeException(env, "enable shutter sound failed");
return JNI_FALSE;
}
}
JNI 的拍照音代码中调用
status_t rc = camera->sendCommand(CAMERA_CMD_ENABLE_SHUTTER_SOUND, value, 0);
定位到 Camera 类
// frameworks\av\camera\Camera.cpp
// send command to camera driver
status_t Camera::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2)
{
ALOGV("sendCommand");
sp <::android::hardware::ICamera> c = mCamera; // 接口类
if (c == 0) return NO_INIT;
return c->sendCommand(cmd, arg1, arg2);
}
::android::hardware::ICamera 是接口类,该类定义了一系列 camera 虚函数
- disconnect/connect 打开关闭相机
- startPreview/stopPreview 启动关闭预览
- startRecording/stopRecording 启动关闭录像
- onTransact binder 通讯
framework camera
结合分析 camera API 1 的经验
Android Camera 二 JNI JAVA和C/CPP图像数据传输流程分析
可以推测出 ICamera 是相机客户端 CameraClient
// frameworks\av\services\camera\libcameraservice\api1\CameraClient.cpp
status_t CameraClient::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {
LOG1("sendCommand (pid %d)", getCallingPid());
int orientation;
Mutex::Autolock lock(mLock);
status_t result = checkPidAndHardware();
if (result != NO_ERROR) return result;
if (cmd == CAMERA_CMD_SET_DISPLAY_ORIENTATION) {
//!++
LOG1("CAMERA_CMD_SET_DISPLAY_ORIENTATION - tid(%d), (degrees, mirror)=(%d, %d)", ::gettid(), arg1, mCameraFacing); //Add debug log
//!--
// Mirror the preview if the camera is front-facing.
orientation = getOrientation(arg1, mCameraFacing == CAMERA_FACING_FRONT);
if (orientation == -1) return BAD_VALUE;
if (mOrientation != orientation) {
mOrientation = orientation;
if (mPreviewWindow != 0) {
mHardware->setPreviewTransform(mOrientation);
}
}
//!++
if(mHardware != 0)
mHardware->sendCommand(cmd, mOrientation, arg2);
//!--
return OK;
} else if (cmd == CAMERA_CMD_ENABLE_SHUTTER_SOUND) {
switch (arg1) {
case 0:
return enableShutterSound(false);
case 1:
return enableShutterSound(true);
default:
return BAD_VALUE;
}
return OK;
} else if (cmd == CAMERA_CMD_PLAY_RECORDING_SOUND) { // 拍照音
sCameraService->playSound(CameraService::SOUND_RECORDING_START);
} else if (cmd == CAMERA_CMD_SET_VIDEO_BUFFER_COUNT) {
// Silently ignore this command
return INVALID_OPERATION;
} else if (cmd == CAMERA_CMD_PING) {
// If mHardware is 0, checkPidAndHardware will return error.
return OK;
}
return mHardware->sendCommand(cmd, arg1, arg2);
}
定位到 sCameraService->playSound(CameraService::SOUND_RECORDING_START);
查找 sCameraService 的声明
在 CameraService.h 声明类 class BasicClient 中声明了 static sp<CameraService> sCameraService;
接下来分析到类 CameraService 定位到 playSound 方法
// frameworks\av\services\camera\libcameraservice\CameraService.cpp
//!++ 加载相机播放的声音
void CameraService::loadSoundImp() {
LOG1("[CameraService::loadSoundImp] E");
mSoundPlayer[SOUND_SHUTTER] = newMediaPlayer("/system/media/audio/ui/camera_click.ogg");
mSoundPlayer[SOUND_RECORDING_START] = newMediaPlayer("/system/media/audio/ui/VideoRecord.ogg");
mSoundPlayer[SOUND_RECORDING_STOP] = newMediaPlayer("/system/media/audio/ui/VideoStop.ogg");
LOG1("[CameraService::loadSoundImp] X");
}
void* CameraService::loadSoundThread(void* arg) {
LOG1("[CameraService::loadSoundThread]");
CameraService* pCameraService = (CameraService*)arg;
pCameraService->loadSoundImp();
pthread_exit(NULL);
return NULL;
}
//!--
void CameraService::releaseSound() {
Mutex::Autolock lock(mSoundLock);
LOG1("CameraService::releaseSound ref=%d", mSoundRef);
if (--mSoundRef) return;
//!++
waitloadSoundDone();
//!--
for (int i = 0; i < NUM_SOUNDS; i++) {
if (mSoundPlayer[i] != 0) {
mSoundPlayer[i]->disconnect();
mSoundPlayer[i].clear();
}
}
}
void CameraService::playSound(sound_kind kind) {
ATRACE_CALL();
ALOGD("AAAAA bbbplaySound");
// return;
LOG1("playSound(%d)", kind);
Mutex::Autolock lock(mSoundLock);
//!++
waitloadSoundDone();
//!--
sp<MediaPlayer> player = mSoundPlayer[kind];
if (player != 0) {
player->seekTo(0);
player->start(); // 播放声音
}
}