setMicrophoneMute()如何工作?

ate*_*iob 30 android microphone android-audiomanager

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

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

这引出了一个问题:是否AudioManager.setMicrophoneMute()有效?它只是一个存根方法,等待在未来的Android版本中实现吗?如果没有,它是如何工作的?我需要做些什么才能让它发挥作用?有什么条件让它的名字意味着它起作用?

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

此方法仅应由替换平台范围的音频设置管理或主要电话应用程序的应用程序使用.

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

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

  1. 该标志(数据库中的SET_MIC_MUTE)是如何使用的?
  2. 该标志何时实际断开麦克风信号与手机内的前置放大器电路的连接?
  3. 如果不这样做,谁做到了?
  4. 如果没有这样做,这个"静音"怎么会起作用呢?

请解释.谢谢.

BMB*_*BMB 23

要详细说明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();
}
Run Code Online (Sandbox Code Playgroud)

实际上是将麦克风静音的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;
    ...
    }
}
Run Code Online (Sandbox Code Playgroud)

并调用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;
}
Run Code Online (Sandbox Code Playgroud)

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

有关硬件插入方式的更多信息,请研究AudioHardwareInterface.cpp文件.基本上它最终出现在一个libhardware中,对createAudioHardware进行了外部C调用,该调用为平台插入了正确的AudioHardWare.还有用于使用基于A2DP的硬件的开关,用于仿真器的通用硬件和用于存储音频的硬件.假设您正在使用实际设备,那么实现非常依赖于硬件.为了感受它,我们可以使用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;
}
Run Code Online (Sandbox Code Playgroud)

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

为您的另外4个问题提供简短版本:

  1. 该标志通过几层代码传递,直到它最终出现在硬件特定的静音麦克风中.

  2. 当硬件特定代码运行时,麦克风将断开连接,除非至少在某些设备上进行通话.

  3. 当setMicrophoneMute不使麦克风静音时,即在通话时,可以使用其中一个电话API:s,我建议学习手机应用程序.

  4. 基于当前的实现,静音似乎在不在通话中时起作用,但在我们尚未研究的平台上可能存在硬件特定问题.

编辑:

是否有更多的挖掘以及向调制解调器CPU发送静音命令的方法是通过内部Phone接口,该接口是SDK开发人员无法使用的com.android.internal.telephony包的一部分.根据评论,你看到这个功能只能由替换音频管理或原始电话应用程序的应用程序使用,我猜想AudioManager.setMicrophoneMute()应始终将麦克风静音.但由于其他应用程序可能使用此功能,因此他们在硬件实现中添加了一项检查,以免弄乱手机应用程序的状态,该应用程序跟踪静音连接以及麦克风.由于硬件实现细节以及静音是一个比考虑呼叫状态时最初想的更复杂的操作,因此该功能可能不会正常工作.


an0*_*00b 12

尝试查看AudioManager源代码:

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

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

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

反过来,它将它委托给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);
}
Run Code Online (Sandbox Code Playgroud)

反过来,它将它委托给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();
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,但我仍然不明白它是如何工作的。我所看到的是,它要经过许多层和包装程序才能基本设置或清除某些数据库中的标志。但是该标志如何使用?该标志何时真正断开电话内的前置放大器电路的麦克风信号?如果没有,那是谁做的?如果没有采取任何措施,那么这种“静音”应该如何工作?请解释。+1。 (2认同)

ale*_*n02 8

我在三星Galaxy上发现了同样的问题,我通过使用MODE_IN_COMMUNICATION模式解决了它.

在AudioManager.java源代码中说:

  1. MODE_IN_CALL - 在通话音频模式下.建立电话呼叫.
  2. MODE_IN_COMMUNICATION - 在通信音频模式下.建立音频/视频聊天或VoIP呼叫.

因为我使用第三个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);
Run Code Online (Sandbox Code Playgroud)