为了详细说明上面的 00b: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();
}
其实就是让麦克风静音的Binder事务。 Binder 调用的接收端如下所示:
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;
...
}
}
并调用 setMicMute 的实际实现音频调频器 http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=services/audioflinger/AudioFlinger.cpp;h=c68e20d6304072d88f7a79180ffe845b5ad0eac1;hb=a8313e71fe8b483448d14e22610101c5f3672744。下一步是查看这个函数:
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 中,并通过 extern C 调用 createAudioHardware,该调用会为平台插入正确的 AudioHardWare。还有一些开关用于使用基于 A2DP 的硬件,这是一种用于仿真器和存根音频的通用硬件。假设您正在使用实际设备,那么实现很大程度上取决于硬件。为了感受一下它,我们可以使用 Crespo (Nexus S) 的可用音频硬件作为示例。
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;
}
基于这个例子,我们可以讨论智能手机中音频路由的实现。正如您在 Crespo 实现中所看到的,只有当您不在通话中时,麦克风静音呼叫才会被尊重。原因是音频是通过模拟基带路由的,模拟基带处理功率调节、放大和其他事情。通话时,语音音频通常由模拟基带和调制解调器 CPU 一起处理,而不是通过应用程序 CPU 路由。在这种情况下,您可能需要通过 RIL 通过调制解调器 CPU 才能将麦克风静音。但由于这种行为依赖于硬件,因此没有通用的解决方案。
针对您的 4 个附加问题提供简短版本:
该标志通过几层代码传递,直到它最终到达硬件特定的静音麦克风。
当硬件特定代码运行时,麦克风会断开连接,至少在某些设备上通话时除外。
当 setMicrophoneMute 不使麦克风静音时,即在通话时,可以使用电话 API 之一来做到这一点,我建议研究电话应用程序。
根据当前的实现,静音似乎在不通话时有效,但我们在此未研究的平台上可能存在特定于硬件的问题。
EDIT:
经过进一步挖掘,向调制解调器 CPU 发送静音命令的方法是通过内部电话接口,该接口是 com.android.internal.telephony 包的一部分,但 SDK 开发人员无法使用。根据您看到的评论,该函数只能由替换音频管理或原始电话应用程序的应用程序使用,我猜测 AudioManager.setMicrophoneMute() 应该始终使麦克风静音。但由于其他应用程序可能使用此功能,因此他们在硬件实现中添加了一个检查,以免弄乱电话应用程序的状态,该应用程序跟踪静音连接以及麦克风。由于硬件实现细节以及静音是一项比人们在考虑呼叫状态时最初想象的要复杂得多的操作这一事实,该功能现在可能无法按预期工作。