我一直在尝试使用 Android 的 AudioManager.setMicrophoneMute()
但没有取得太大成功。也就是说,无论我做什么,它都拒绝将麦克风静音。
我在网上搜索了一些线索,发现了一些报告类似经历的参考文献:
//stackoverflow.com/questions/3043330/unable-to-mute-the-microphone-in-android ">无法 问题:AudioManager.setMicrophoneMute()
是否有效?它只是一个存根方法,等待在 Android 的未来版本中实现吗?如果没有,它是如何工作的?我需要什么才能让它发挥作用?正如其名称所暗示的那样,其工作的条件是什么?
编辑:我注意到此方法的文档说:
此方法只能由替换的应用程序使用
音频设置或主要电话的全平台管理
应用程序。
这意味着什么?为什么我要更换平台范围的管理?我真的需要这样做吗?如果是这样,我该怎么做?
编辑:下面的答案很好,但我仍然不明白:
- 如何使用该标志(数据库中的 SET_MIC_MUTE)?
- 该标志何时真正断开麦克风信号
手机内部的前置放大电路?
- 如果它不这样做,那么谁会这样做?
- 如果没有任何作用,那么这种“静音”将如何发挥作用?
请解释一下。谢谢。
I have been trying to use Android's AudioManager.setMicrophoneMute()
without much success. That is, it simply refuses to mute the microphone, no matter what I do.
I searched the web for some clues and I found several references reporting similar experience:
Which begs the question: Does AudioManager.setMicrophoneMute()
work at all? Is it only a stub method, waiting to be implemented in some future version of Android? If not, how does it work? What do I need to make it work? What are the conditions that make it work as its name implies?
EDIT: I noticed that the documentation for this method says:
This method should only be used by applications that replace the
platform-wide management of audio settings or the main telephony
application.
What does this mean? Why would I want to replace the platform-wide management? Do I really need to do that? If so, how do I do that?
EDIT: The answer below is great but I still don't understand:
- How is that flag (SET_MIC_MUTE in database) being used?
- When does this flag actually disconnect the microphone signal from
the pre-amplifier circuit inside the phone?
- If it doesn't do that, who does that?
- If nothing does that, how is this "mute" expected to work?
Please explain. Thanks.
发布评论
评论(3)
为了详细说明上面的 00b:s 答案和问题的编辑版本,我们必须更深入地挖掘源代码。 IAudioflinger 是 AudioFlinger 服务的接口,调用的
实际上是 Binder 事务,用于将麦克风静音。 Binder 调用的接收端如下所示:
并调用 AudioFlinger。下一步是看这个函数:
这里我们可以注意两件事。首先是进行权限检查,以便能够将麦克风静音。在 settingsAllowed 中检查的权限是 android.permission.MODIFY_AUDIO_SETTINGS,因此如上面的评论之一所述,静音麦克风的第一个要求是您的应用程序已声明它需要此权限。接下来要注意的是,我们现在使用 mAudioHardware->setMicMute(state) 调用 setMicMute 的硬件特定版本。
有关硬件插入方式的更多信息,请研究文件 AudioHardwareInterface.cpp。基本上,它最终会出现在一个 libhardware 中,并通过 extern C 调用 createAudioHardware,该调用会为平台插入正确的 AudioHardWare。还有一些开关用于使用基于 A2DP 的硬件,这是一种用于仿真器和存根音频的通用硬件。假设您正在使用实际设备,那么实现很大程度上取决于硬件。为了感受一下它,我们可以使用 Crespo (Nexus S) 的可用音频硬件作为示例。
基于这个例子,我们可以讨论智能手机中音频路由的实现。正如您在 Crespo 实现中所看到的,只有当您不在通话中时,麦克风静音呼叫才会被尊重。原因是音频是通过模拟基带路由的,模拟基带处理功率调节、放大和其他事情。通话时,语音音频通常由模拟基带和调制解调器 CPU 一起处理,而不是通过应用程序 CPU 路由。在这种情况下,您可能需要通过 RIL 通过调制解调器 CPU 才能将麦克风静音。但由于这种行为依赖于硬件,因此没有通用的解决方案。
为了给您的 4 个附加问题提供简短版本:
该标志通过几层代码传递,直到它最终到达硬件特定的静音麦克风。
当硬件特定代码运行时,麦克风会断开连接,除非至少在某些设备上处于通话状态。
当 setMicrophoneMute 不将麦克风静音时,即在通话时可以使用电话 API 之一来实现这一点,我建议研究电话应用程序。
基于当前的实现,静音似乎在未通话时有效,但我们在此未研究的平台上可能存在特定于硬件的问题。
编辑:
进行了更多挖掘,将静音命令发送到调制解调器 CPU 的方法是通过内部电话接口,该接口是 com.android.internal.telephony 包的一部分,但 SDK 不可用开发商。根据您看到的评论,该函数只能由替换音频管理或原始电话应用程序的应用程序使用,我猜测 AudioManager.setMicrophoneMute() 应该始终使麦克风静音。但由于其他应用程序可能使用此功能,因此他们在硬件实现中添加了一个检查,以免弄乱电话应用程序的状态,该应用程序跟踪静音连接以及麦克风。由于硬件实现细节以及静音是一项比人们在考虑呼叫状态时最初想象的要复杂得多的操作这一事实,该功能现在可能无法按预期工作。
To elaborate on an00b:s answer above and the edited version of the question we have to dig deeper into the source code. IAudioflinger is the interface to the AudioFlinger service and the call to
is actually the Binder transaction to mute the microphone. The receiving side of the Binder call looks like:
and calls to the actual implementation of setMicMute in the AudioFlinger. Next step is to look at this function:
Here we can note two things. The first is that there is a permissions check to be able to mute the microphone. The permission being checked for in settingsAllowed is android.permission.MODIFY_AUDIO_SETTINGS so as mentioned in one of the comments above the first requirement for muting the microphone is that your application has declared that it needs this permission. The next thing to note is that we now call in to the hardware specific version of setMicMute using mAudioHardware->setMicMute(state).
For more info on the way the hardware is plugged study the file AudioHardwareInterface.cpp. Basically it ends up in a libhardware with an extern C call to createAudioHardware which plugs in the correct AudioHardWare for the platform. There are also switches for using an A2DP based hardware, a generic one for the emulator and stubbing the audio. Assumed that you are working on an actual device the implementation is then very much hardware depending. To get a feel for it we can use the available audiohardware from Crespo (Nexus S) as an example.
Based on this example we may wrap up with a discussion of the implementation of audio routing in smartphones. As you can see in the Crespo implementation the mic mute call will only be respected if you are not in a call. The reason for this is that audio is routed through the analog baseband which handles power regulation, amplification and other things. When in a call the voice audio is often handled by analog baseband and modem CPU together and is not routed throught the application CPU. In that case you may need to go through the modem CPU through the RIL in order to mute the microphone. But since this behavior is hardware dependent there is no general solution.
To give the short version to your 4 additional questions:
The flag is passed on through several layers of code until it ends up in the hardware specific mute microphone.
The mic is disconnected when the hardware specific code has run except when in a call at least on some devices.
When setMicrophoneMute does not mute the mic, i.e. when in a call it may be possible to do that using one of the telephony API:s, I would suggest studying the phone app.
Based on the current implementation mute seems to work when not in a call but there may be hardware specific issues on platforms we have not studied here.
EDIT:
Did some more digging and the way to send a mute command to the modem CPU is via the internal Phone interface that is part of the com.android.internal.telephony package that is not available to SDK developers. Based on the comment you saw that this function should only be used by applications that replace audio management or the original telephony application I would guess that AudioManager.setMicrophoneMute() was supposed to always mute the microphone regardless. But since other applications probably use this they added a check in the hardware implementation in order not to mess up the state of the phone application which keeps track of muted connections as well as the microphone. The function is probably not working as supposed to right now due to hardware implementation details and the fact that mute is a much more complex operation than one would initially think when considering call states as well.
尝试查看 AudioManager 源代码:
将麦克风静音的任务委托给名为IAudioService:
反过来,将其委托给 AudioSystem 似乎是在 本机代码:
反过来,将其委托给IAudioFlinger 可以在 IAudioFlinger.cpp:
Try looking at the AudioManager source code:
The task of muting the microphone is delegated to a service named IAudioService:
Which, in turn, delegates it to AudioSystem which seems to be implemented in native code:
Which, in turn, delegates it to IAudioFlinger as can be found in IAudioFlinger.cpp:
我在三星 Galaxy 上发现了同样的问题,并通过使用
MODE_IN_COMMUNICATION
模式解决了它。在 AudioManager.java 源代码中,它表示:
MODE_IN_CALL
- 处于通话音频模式。电话呼叫已建立。MODE_IN_COMMUNICATION
- 处于通信音频模式。建立音频/视频聊天或 VoIP 呼叫。因为我使用第三个 VOIP 库,所以我使用
MODE_IN_COMMUNICATION
它解决了问题。I found the same issues on samsung Galaxy and I solved it by using
MODE_IN_COMMUNICATION
mode.In the AudioManager.java source codeit says :
MODE_IN_CALL
- In call audio mode. A telephony call is established.MODE_IN_COMMUNICATION
- In communication audio mode. An audio/video chat or VoIP call is established.Because i use the third VOIP library, I use the
MODE_IN_COMMUNICATION
and it solved the issue.