博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
android 录像提示音问题
阅读量:6275 次
发布时间:2019-06-22

本文共 4632 字,大约阅读时间需要 15 分钟。

本文转自我的博客

选中拍摄时关闭声音,摄像时会有声音,设备:小米note,红米note,oppo

据查该问题属于一种防偷拍的潜规则类型设置,与android系统提供商相关,拍照/摄像的提示音所有实现都在底层实现,上层能够控制的有限。

为什么拍照可以实现静默?

静默拍照目前可以通过两种方式设置:

  1. android4.2以上的版本可以通过Camera提供的enableShutterSound(boolean enabled)方法禁止拍照提示音;
  2. 通过调整接口使用来规避提示音,设置shutter callback为null来实现,该方法在中有提及;

这两种方法在底层的实现原理如下:

以android4.2的源码 为例,最终的提示音调用代码目录在:

// snapshot taken callbackvoid CameraClient::handleShutter(void) {    //mPlayShutterSound 该值从上层设置 即第一种方法提供的接口实现,4.2以上版本有效    if (mPlayShutterSound) {        //声音调用        mCameraService- >playSound(CameraService::SOUND_SHUTTER);    }    sp
c = mCameraClient; if (c != 0) { mLock.unlock(); c->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0); if (!lockIfMessageWanted(CAMERA_MSG_SHUTTER)) return; } disableMsgType(CAMERA_MSG_SHUTTER); mLock.unlock();}

留意一下handleShutter的调用情况,可以发现在CameraClient中仅有一处调用了该函数:

void CameraClient::notifyCallback(int32_t msgType, int32_t ext1,        int32_t ext2, void* user) {    LOG2("notifyCallback(%d)", msgType);    Mutex* lock = getClientLockFromCookie(user);    if (lock == NULL) return;    Mutex::Autolock alock(*lock);    CameraClient* client =            static_cast
(getClientFromCookie(user)); if (client == NULL) return; if (!client->lockIfMessageWanted(msgType)) return; switch (msgType) { case CAMERA_MSG_SHUTTER: // 控制发声 // ext1 is the dimension of the yuv picture. client->handleShutter(); break; default: client->handleGenericNotify(msgType, ext1, ext2); break; }}

那么第二种规避发声的方法也有了合理的解释,底层的快门声调用放在了notifyCallback中,那么躲开了该回调的使用也就避开了快门的声音。

那么摄像的提示音呢?

摄像功能在java层是通过 MediaRecorder 类实现的,但是在java层包括它对应的jni层大多也只是包裹一个接口、注册等作用,到底层最后的实现还是在CameraClient类中,与提示音有关的代码如下:

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);    //提示音代码    mCameraService->playSound(CameraService::SOUND_RECORDING);    result = mHardware->startRecording();    if (result != NO_ERROR) {        ALOGE("mHardware->startRecording() failed with status %d", result);    }    return result;}

关联代码上下文可以发现startRecordingMode本函数无法规避,想要通过该类实现录像功能这是必走的流程,所以相对而言正规取巧的方法在上层理论上无法操控。能够看出的是4.2中也没有预留标志位给上层去控制。

一些野路子方法如下:

  • 方案一:拍摄开始时设置系统音频流静默并调整音量为0,结束时恢复;
  • 方案二:找到提示音文件,通过改名/移动等方法让发音失灵,由于音频文件在系统中,所以需要root权限,该方案对用户要求比较高,不考虑;

经过测试,方案一能够搞定一部分机型的情况,但不是所有的,如中兴、小米的机器都是无效的,在一篇博客中找到了一种解释:

但是需要注意的是:很多机器是强制快门音的,也就是说你在app里调用上述接口也许根本不起作用,你明明enableShutterSound(false)了,但是拍照的时候快门音照样响起,原因在于烧制的系统版本里面有一个值被写死了:ro.camera.sound.forced = 1

在CameraClient代码中找一下这个系统属性值可以找到:

// enable shutter soundstatus_t CameraClient::enableShutterSound(bool enable) {    LOG1("enableShutterSound (pid %d)", getCallingPid());    status_t result = checkPidAndHardware();    if (result != NO_ERROR) return result;    if (enable) {        mPlayShutterSound = true;        return OK;    }    // Disabling shutter sound may not be allowed. In that case only    // allow the mediaserver process to disable the sound.    char value[PROPERTY_VALUE_MAX];    //取到系统值来控制 mPlayShutterSound 设置权限    property_get("ro.camera.sound.forced", value, "0");    if (strcmp(value, "0") != 0) {        // Disabling shutter sound is not allowed. Deny if the current        // process is not mediaserver.        if (getCallingPid() != getpid()) {            ALOGE("Failed to disable shutter sound. Permission denied (pid %d)", getCallingPid());            return PERMISSION_DENIED;        }    }    mPlayShutterSound = false;    return OK;}

那么很明显,在CameraClient中这个系统值的作用就是限制 mPlayShutterSound 的设置了,也是对引文那一段的解释。我们在源码的全局范围内,可以发现除了 mPlayShutterSound 该值相关的几个cpp类中有相关的使用以外,audio_policy_hal.cpp 在该类中也可以找到对forced值的使用,经过查询可以了解到这部分是实现了提示音无视静音的功能,原理大概是在播放提示音的时候会将音量调到最大,详细的过程讲解博客见。也就是说部分设置了ro.camera.sound.forced 的系统,采用强制静音或者调音量的方法行不通,该问题基本无解。

从测试的情况看,ZTE Q801L是可以通过命令获取到ro.camera.sound.forced为1的,实现上确实无法静默拍摄;而小米则比较有意思,首先它无法获取到forced值,但是从表现上看小米原生的相机是静默的、第三方的相机则静默不了,可以推测是MiUI内部有相关的内部接口或者公用属性去设置来控制。

结论

对于无root的应用层而言,使用系统提供的MediaRecorder实现的,针对系统的不同有以下几种情况:

  1. 系统强制发音,设置了ro.camera.sound.forced的,无解;-- 如中兴ZTE Q801L
  2. 定制化系统提供了内部接口的并且外在表现为强制发音的,暂时无解。或许可以有针对性的的对相关的定制系统查找相关的方法;--如小米note、红米note
  3. 系统未强制设定的,一部分无需设置(如htc、三星);一部分可以通过提供静音策略来限制,这部分要保证不引发其他的音频类型问题;(魅族?)

除此之外,自定义编写视频录制实现也是个方案,不过工作量需要评估。

转载地址:http://aegpa.baihongyu.com/

你可能感兴趣的文章
poi 导入导出的api说明(大全)
查看>>
Mono for Android 优势与劣势
查看>>
将图片转成base64字符串并在JSP页面显示的Java代码
查看>>
js 面试题
查看>>
sqoop数据迁移(基于Hadoop和关系数据库服务器之间传送数据)
查看>>
腾讯云下安装 nodejs + 实现 Nginx 反向代理
查看>>
Javascript 中的 Array 操作
查看>>
java中包容易出现的错误及权限问题
查看>>
AngularJS之初级Route【一】(六)
查看>>
服务器硬件问题整理的一点总结
查看>>
SAP S/4HANA Cloud: Revolutionizing the Next Generation of Cloud ERP
查看>>
Mellanox公司计划利用系统芯片提升存储产品速度
查看>>
白帽子守护网络安全,高薪酬成大学生就业首选!
查看>>
ARM想将芯片装进人类大脑 降低能耗是一大挑战
查看>>
Oracle数据库的备份方法
查看>>
Selenium 自动登录考勤系统
查看>>
关于如何以编程的方式执行TestNG
查看>>
智能照明造福千家万户 家居智能不再是梦
查看>>
物联网如何跳出“看起来很美”?
查看>>
浅谈MySQL 数据库性能优化
查看>>