setMicrophoneMute()如何工作?

我一直试图使用Android的AudioManager.setMicrophoneMute()没有太多的成功。 也就是说,无论我做什么,它都会拒绝将麦克风静音。

我在网上search了一些线索,发现有几个参考文献报道了类似的经历:

  • AudioManger.setMicrophoneMutefunction不工作?
  • setMicrophoneMute(boolean)在某些设备上不起作用
  • 无法在Android中将麦克风静音

这引出了一个问题: AudioManager.setMicrophoneMute()是否工作? 它只是一个存根方法,等待在未来的Android版本中实现? 如果不是,它是如何工作的? 我需要什么来使它工作? 它的名字意味着什么使它的工作的条件?

编辑:我注意到这个方法的文档说:

这种方法只能由替代audio设置或主电话应用程序的平台范围pipe理的应用程序使用。

这是什么意思? 为什么要replace平台范围的pipe理? 我真的需要这样做吗? 如果是这样,我该怎么做?

编辑:下面的答案是伟大的,但我还是不明白:

  1. 该标志(数据库中的SET_MIC_MUTE)是如何被使用的?
  2. 什么时候该标志实际上从手机内部的前置放大器电路断开麦克风信号?
  3. 如果不这样做,谁来做?
  4. 如果没有,那么这个“哑巴”是如何工作的?

请解释。 谢谢。

Solutions Collecting From Web of "setMicrophoneMute()如何工作?"

为了详细说明上面的an00b:s的答案和问题的编辑版本,我们必须深入了解源代码。 IAudioflinger是AudioFlinger服务和调用的接口

 virtual status_t setMicMute(bool state) { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); data.writeInt32(state); remote()->transact(SET_MIC_MUTE, data, &reply); return reply.readInt32(); } 

实际上是用于使麦克风静音的活页夹事务。 活页夹调用的接收方如下所示:

  status_t BnAudioFlinger::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { ... case SET_MIC_MUTE: { CHECK_INTERFACE(IAudioFlinger, data, reply); int state = data.readInt32(); reply->writeInt32( setMicMute(state) ); return NO_ERROR; } break; ... }} 

并调用AudioFlinger中的setMicMute的实际实现。 下一步是看这个函数:

  status_t AudioFlinger::setMicMute(bool state) { // check calling permissions if (!settingsAllowed()) { return PERMISSION_DENIED; } AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_HW_SET_MIC_MUTE; status_t ret = mAudioHardware->setMicMute(state); mHardwareStatus = AUDIO_HW_IDLE; return ret; } 

这里我们可以注意到两件事情。 首先是有一个权限检查,可以静音麦克风。 settingsAllowed中正在检查的权限是android.permission.MODIFY_AUDIO_SETTINGS,如上面的注释之一所述,用于静音麦克风的第一个要求是您的应用程序已声明它需要此权限。 接下来要注意的是,我们现在使用mAudioHardware-> setMicMute(state)来调用setMicMute的硬件特定版本。

有关硬件插入方式的更多信息,请查阅文件AudioHardwareInterface.cpp。 基本上,它最终在一个libhardware与外部C调用createAudioHardware插入正确的AudioHardWare平台。 还有一些开关用于使用基于A2DP的硬件,一种是仿真器的通用硬件,另一种是用于存储audio。 假设你在一个实际的设备上工作,那么实现是非常依赖于硬件的。 为了获得它的感觉,我们可以使用Crespo(Nexus S)提供的audio硬件为例。

  status_t AudioHardware::setMicMute(bool state) { LOGV("setMicMute(%d) mMicMute %d", state, mMicMute); sp<AudioStreamInALSA> spIn; { AutoMutex lock(mLock); if (mMicMute != state) { mMicMute = state; // in call mute is handled by RIL if (mMode != AudioSystem::MODE_IN_CALL) { spIn = getActiveInput_l(); } } } if (spIn != 0) { spIn->standby(); } return NO_ERROR; } 

基于这个例子,我们可以结束对智能手机中audio路由实现的讨论。 正如您在Crespo实施中看到的那样,只有在您不在通话的情况下才能遵守麦克风静音。 其原因是audio通过处理功率调节,放大和其他事情的模拟基带进行路由。 在通话过程中,语音audio通常由模拟基带和调制解调器CPU一起处理,不通过应用CPU进行路由。 在这种情况下,您可能需要通过RIL通过调制解调器CPU才能使麦克风静音。 但是由于这种行为是依赖于硬件的,所以没有通用的解决scheme

给你的4个附加问题的简短版本:

  1. 该标志通过几层代码传递,直到它结束在硬件特定的静音麦克风。

  2. 当硬件特定的代码已经运行,除了在至less一些设备上的呼叫时,麦克风被断开。

  3. 当setMicrophoneMute不会使麦克风静音时,即在通话中使用电话API之一可能会这样做,我会build议学习电话应用程序。

  4. 基于目前的实现静音似乎工作,而不是在通话,但可能是我们没有在这里研究的平台上硬件的具体问题。

编辑:

做了更多的挖掘以及向调制解调器CPU发送静音命令的方式是通过作为com.android.internal.telephony包的一部分的内部电话接口,SDK开发人员不可用。 根据评论你看到,这个function只能用于替代audiopipe理或原来的电话应用程序的应用程序,我猜测AudioManager.setMicrophoneMute()应该始终使麦克风静音。 但是由于其他应用程序可能会使用这个function,所以他们在硬件实现中添加了一个检查,以免弄乱跟踪静音连接以及麦克风的电话应用程序的状态。 由于硬件实现的细节以及静音是一个复杂的操作,因此该function可能不会像现在这样工作。

试着看看AudioManager的源代码 :

 public void setMicrophoneMute(boolean on){ IAudioService service = getService(); try { service.setMicrophoneMute(on); } catch (RemoteException e) { Log.e(TAG, "Dead object in setMicrophoneMute", e); } } 

将麦克风静音的任务委托给名为IAudioService的服务:

 public void setMicrophoneMute(boolean on) { if (!checkAudioSettingsPermission("setMicrophoneMute()")) { return; } synchronized (mSettingsLock) { if (on != mMicMute) { AudioSystem.muteMicrophone(on); mMicMute = on; } } } 

而后者又将其委托给AudioSystem ,这似乎是用本机代码实现的:

 status_t AudioSystem::muteMicrophone(bool state) { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; return af->setMicMute(state); } 

然后将其委派给IAudioFlinger,如IAudioFlinger.cpp中所示 :

 virtual status_t setMicMute(bool state) { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); data.writeInt32(state); remote()->transact(SET_MIC_MUTE, data, &reply); return reply.readInt32(); } 

伙计们。 我在三星Galaxy上发现了相同的问题,我解决了使用MODE_IN_COMMUNICATION模式。 我在AudioManager.java源代码中看到,它说:1.MODE_IN_CALL – '在通话audio模式。 电话呼叫build立。 2.MODE_IN_COMMUNICATION – '在通讯audio模式。 audio/video聊天或VoIP呼叫build立。 因为我使用第三个VOIP库,然后我使用MODE_IN_COMMUNICATION并解决了这个问题。 喜欢这个:

  AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); // get original mode int originalMode = audioManager.getMode(); audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); // change mute boolean state = !audioManager.isMicrophoneMute(); audioManager.setMicrophoneMute(state); // set mode back audioManager.setMode(originalMode); 

出于某种原因,我发现这个post时发生了错误。 以下是我所了解到的有关设备setMicrophoneMute()所做的工作的一些信息,以及有哪些方法可以解决这个问题 – 当然不是一个完美的解决scheme! setMicrophoneMute(boolean)在某些设备上不起作用