前面已经针对拍照快门声音控制流程进行了分析,接下来分析一下录像快门声音的控制流程。
Android 8.1/9.0 MTK Camera源码分析之快门声音控制流程
这两篇文章其实都是相对于手机系统ROM Camera开发过程中,针对ap层快门声音动态控制来说明的。
早前在Android N以及之前,mtk源码中,/frameworks/base/core/java/android/hardware/Camera.java中是有定义可以控制录像快门声音的公开接口的。而到了Android O之后,camera.java便没有了直接控制的函数了。
由于enableRecordingSound 该接口在Camera.java中去掉了,需要自己添加,才能控制录像快门的音效。
key值为"rec-mute-ogg",调用set函数设置下去。
/**
* @hide
* ljr add for control video shutter sound
*/
private static final String KEY_MUTE_RECORDING_SOUND = "rec-mute-ogg";
/**
* Whether the recording sound can be disabled.
* ljr add for control video shutter sound
* @hide
*/
public void enableRecordingSound(String value) {
if (value.equals("1") || value.equals("0")) {
set(KEY_MUTE_RECORDING_SOUND, value);
}
}
录像快门声音,正常逻辑,一定是执行开始视频录制时进行播放的。所以这里可以先直接看"rec-mute-ogg"这个key被getValue的地方。
文件路径:frameworks/av/services/camera/libcameraservice/api1/CameraClient.cpp
startRecordingMode():
status_t CameraClient::startRecordingMode() {
LOG1("startRecordingMode");
status_t result = NO_ERROR;
// if recording has been enabled, nothing needs to be done
if (mHardware->recordingEnabled()) {
return NO_ERROR;
}
// if preview has not been started, start preview first
if (!mHardware->previewEnabled()) {
result = startPreviewMode();
if (result != NO_ERROR) {
return result;
}
}
// start recording mode
enableMsgType(CAMERA_MSG_VIDEO_FRAME);
//这里拿到Camera Parameters对象,用作获取设置的参数
CameraParameters params(mHardware->getParameters());
int value = 0;
value = params.getInt("rec-mute-ogg"); //通过params来获取rec-mute-ogg值
if (value != 1) { //满足,调用sCameraService来进行声音播放
sCameraService->playSound(CameraService::SOUND_RECORDING_START);
}
result = mHardware->startRecording(); //执行到hal的startRecording
if (result != NO_ERROR) {
ALOGE("mHardware->startRecording() failed with status %d", result);
}
return result;
}
stopRecording():
// stop recording mode
void CameraClient::stopRecording() {
LOG1("stopRecording (pid %d)", getCallingPid());
{
Mutex::Autolock lock(mLock);
if (checkPidAndHardware() != NO_ERROR) return;
disableMsgType(CAMERA_MSG_VIDEO_FRAME);
CameraParameters params(mHardware->getParameters());//通过params来获取rec-mute-ogg值
int value = 0;
value = params.getInt("rec-mute-ogg");
if (value != 1) {//满足,调用sCameraService来进行声音播放
sCameraService->playSound(CameraService::SOUND_RECORDING_STOP);
}
mHardware->stopRecording();//执行到hal的stopRecording
mPreviewBuffer.clear();
}
{
Mutex::Autolock l(mAvailableCallbackBuffersLock);
if (!mAvailableCallbackBuffers.empty()) {
mAvailableCallbackBuffers.clear();
}
}
}
CameraService.cpp中的playsound函数:
void CameraService::playSound(sound_kind kind) {
ATRACE_CALL();
LOG1("playSound(%d)", kind);
Mutex::Autolock lock(mSoundLock);
//!++
waitloadSoundDone(); //资源加载
//!--
sp<MediaPlayer> player = mSoundPlayer[kind];
if (player != 0) {
player->seekTo(0);
player->start();
}
}
添加之后,在app中调用api控制录像声音:
parameters.enableRecordingSound(isShutterSoundOn ? "0" : "1");
api2同样会方便很多,仅需在上层startRecording和stopRecording中控制即可。
mICameraContext.getSoundPlayback().play(ISoundPlayback.START_VIDEO_RECORDING);
@Override
public void startRecording() {
LogHelper.i(TAG, "[startRecording] + ");
mIsRecording = true;
if(isShutterSoundOn()) { //ljr modify
mICameraContext.getSoundPlayback().play(ISoundPlayback.START_VIDEO_RECORDING);
}
try {
CaptureRequest.Builder builder = doCreateAndConfigRequest(true);
setRepeatingRequest(builder);
} catch (CameraAccessException e) {
e.printStackTrace();
}
LogHelper.d(TAG, "[startRecording] - ");
}
Camera api2在快门声音这一点上确实比api1要简洁很多。可以做到完全在上层控制。
而在api1中,快门声音播放方式放到cameraservice中,主要原因还是设计上要做到快门声音与拍照结束进行同步,也就是说快门声音播放了,表明照片已经捕获成功。而如果在上层进行播放的话,是没有直接的回调来判断照片捕获成功的时机。但api2直接就给我们提供了captureSession的回调,可以用作判断,再把声音播放方式放在上层就简洁多了。
录像声音也是一样,放在cameraservice中,主要也是控制在真正执行recording函数之前播放,以免录像快门声音也被录制进视频中。而mtk在Android N之后的改变,去除camera.java的直接控制录像快门声音的接口,大概也是想让我们直接在上层调用StartRecording或StopRecording时直接控制就可以。