草庐IT

android - setMicrophoneMute() 是如何工作的?

coder 2023-06-06 原文

我一直在尝试使用 Android 的 AudioManager.setMicrophoneMute(),但没有取得多大成功。也就是说,无论我做什么,它都拒绝让麦克风静音。

我在网上搜索了一些线索,并找到了一些报告类似经历的引用资料:

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

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

This method should only be used by applications that replace the platform-wide management of audio settings or the main telephony application.

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

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

  1. 如何使用该标志(数据库中的 SET_MIC_MUTE)?
  2. 此标志何时真正断开麦克风信号与 手机内部的前置放大电路?
  3. 如果不这样做,谁来做?
  4. 如果不这样做,这个“静音”应该如何工作?

请解释一下。谢谢。

最佳答案

要详细说明上面的 an00b:s 答案和问题的编辑版本,我们必须更深入地挖掘源代码。 IAudioflinger 是 AudioFlinger 服务的接口(interface)和对

的调用
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 中调用 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 中,通过 extern C 调用 createAudioHardware 为平台插入正确的 AudioHardWare。还有一些用于使用基于 A2DP 的硬件的开关,一种用于仿真器的通用硬件和 stub 音频。假设您正在使用实际设备,那么实现很大程度上取决于硬件。为了感受它,我们可以使用来自 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 个附加问题提供简短版本:

  1. 标志通过几层代码传递,直到最终到达硬件特定的静音麦克风。

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

  3. 当 setMicrophoneMute 不使麦克风静音时,即在通话时,可以使用其中一个电话 API:s 来做到这一点,我建议研究电话应用程序。

  4. 根据当前的实现,静音似乎在不通话时可以工作,但在我们未在此处研究的平台上可能存在特定于硬件的问题。

编辑:

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

关于android - setMicrophoneMute() 是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6874881/

有关android - setMicrophoneMute() 是如何工作的?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  4. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  5. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  6. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  7. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  8. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  9. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  10. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

随机推荐