要详细说明an00b上面的答案和编辑过的问题,我们需要深入挖掘源代码。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;
...
}
}
接下来需要查看这个函数:AudioFlinger.cpp中setMicMute的实际实现。
status_t AudioFlinger::setMicMute(bool state) {
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,因此如上面的评论之一所提到的,静音麦克风的第一个要求是您的应用程序已声明需要此权限。另一个需要注意的是,我们现在调用硬件特定版本的setMicMute函数,使用mAudioHardware->setMicMute(state)。
更多关于硬件连接方式的信息,请研究文件AudioHardwareInterface.cpp。基本上,它最终会进入一个名为libhardware的外部C调用,以创建适合平台的正确AudioHardWare。还有针对使用基于A2DP的硬件、模拟器的通用硬件和stubbing audio的开关。假设您正在实际设备上工作,则实现非常依赖于硬件。为了对此有所感觉,我们可以使用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;
if (mMode != AudioSystem::MODE_IN_CALL) {
spIn = getActiveInput_l();
}
}
}
if (spIn != 0) {
spIn->standby();
}
return NO_ERROR;
}
根据这个例子,我们可以讨论智能手机中音频路由的实现。正如您在Crespo实现中所看到的,如果您正在通话中,则只有在没有通话时才会响应麦克风静音调用。原因是音频通过模拟基带路由,该基带处理功率调节、放大和其他事项。在通话中,声音通常由模拟基带和调制解调器CPU共同处理,而不是通过应用CPU进行路由。在这种情况下,您可能需要通过RIL通过调制解调器CPU来静音麦克风。但由于这种行为取决于硬件,因此没有通用解决方案。
回答您的四个附加问题:
1. 标志沿着几层代码传递,直到最终到达特定于硬件的静音麦克风。
2. 在特定于硬件的代码运行后,除了某些设备在通话中保持连接外,麦克风会被断开连接。
3. 当setMicrophoneMute无法静音麦克风时,例如在通话中,可能可使用其中一个电话API来完成。建议研究电话应用程序。
4. 基于当前实现,当没有通话时,静音似乎有效,但是在我们未研究的平台上可能存在特定于硬件的问题。
编辑:
经过进一步调查,向调制解调器CPU发送静音命令的方法是通过com.android.internal.telephony包中的内部Phone接口完成的,该接口不对SDK开发人员提供。基于您看到的评论,声音管理或原始电话应用程序的替代应用程序应使用此功能,我猜测AudioManager.setMicrophoneMute()应始终静音麦克风,而不管其他应用程序是否使用它们,因此在硬件实现中添加了检查,以避免破坏电话应用程序的状态,该应用程序跟踪静音连接以及麦克风。由于静音是一个比一开始考虑时更复杂的操作,并且涉及呼叫状态等,因此此函数现在可能无法按预期工作,这取决于硬件实现细节。
checkAudioSettingsPermission
测试所需的权限呢? - YetAnotherUsersetMicrophoneMute()
改为checkAudioSettingsPermission
,但你知道checkAudioSettingsPermission
做什么以及那个String
参数的含义吗?+1 - ateiob