未调用MacOS Catalina 10.15.7 AudioUnit麦克风通知回调 [英] MacOS Catalina 10.15.7 AudioUnit Microphone notification callback not invoked

查看:87
本文介绍了未调用MacOS Catalina 10.15.7 AudioUnit麦克风通知回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 AudioUnit v2(C) API 在 ObjC++ 中仅使用命令行工具(主要是 clang)构建命令行工具.输出到扬声器工作正常,但从未调用来自麦克风回调的输入.iTerm或终端主机可以根据设置"进行访问.可执行文件还具有嵌入的info.plist,尽管我认为这不相关.

精确的安全模型对我来说还不清楚,如果它起作用的话,它看起来像是一个主要的安全漏洞(从终端运行的任何内容都可以访问):我猜测是由应用"发起的过程具有权限,然后将其传播到任何子进程.但是,这种观点被另一种情况混淆了,在这种情况下,我生成的可执行文件会进行网络访问(因为它是回归测试,因此仅在本地主机上发生),在这种情况下,可执行文件是在请求网络访问,而不是终端.

实际上,源代码是用Felix编写的,然后将其翻译成C ++,然后使用-ObjC选项通过clang进行编译和链接,因此支持嵌入式ObjectiveC.翻译器已经足够成熟,可以在这种简单的应用程序中对其正确性拥有合理的信心.麦克风输入的AudioUnit配置为:

 //配置var outputElement = 0u32;var inputElement = 1u32;//建立回调状态= AudioUnitSetProperty(outputAudioUnit,kAudioOutputUnitProperty_SetInputCallback,kAudioUnitScope_Global,inputElement,(& inputCallback).地址,C_hack :: sizeof [AURenderCallbackStruct] .uint32);断言noErr == status; 

,启用inputElement并禁用outputElement.稍后使用类似的技术构造第二个音频单元,将正弦波泵送到扬声器,并且效果很好.实际的回调仅显示诊断信息并退出,但从未看到该诊断信息.最初,终端没有权限,我们猜测代码是正确的,但是由于缺少访问麦克风的权限而失败.该可执行文件仍然没有权限,但是终端现在可以了(如果我尝试从文件管理器运行该可执行文件,则会弹出一个终端).

在任何阶段都没有错误报告.根本不会调用该回调.

解决方案

要获取回调,您需要

  1. 启用IO
  2. 设置音频单元输入设备

数字2.因为没有必要输出(明智地默认为默认输出设备),所以人们不知所措,在iOS上也没有必要,这可能是因为那里没有音频设备的概念,至少在AudioUnit中没有API.

令人惊讶的是,这两个要求实际上都已记录在案!技术说明2091 涵盖了使用AudioUnits和代码清单3.和4.具有启用IO并设置输入设备的示例代码.清单4.将音频单元输入设备设置为默认输入设备,但是任何输入设备都可以.

从macOS Mojave(10.14)开始,您的Info.plist中需要一个 NSMicrophoneUsageDescription 字符串.否则,您的应用将异常终止.这样,系统会向用户显示提示,要求许可访问输入设备.您可以使用在此处找到代码来控制何时发生.对于命令行工具,可以在链接阶段嵌入 Info.plist 文件.

在Catalina上,您似乎还需要选择启用音频输入的沙箱或强化的运行时(或同时选择两者!).没有这些之一,您的回调将被调用,但是会保持沉默!这两个运行时环境都使用权利"来启用.这些是通过代码签名嵌入到您的应用程序中的元数据,因此您将需要某种形式的代码签名.我认为这不一定意味着您将需要苹果提供的证书,其中有本地/临时"证书.代码签名,它似乎在没有证书的情况下嵌入了权利,尽管我不确定所生成的二进制文件将如何分配.

I am building a command line tool using only command line tools (mainly clang) in ObjC++ using AudioUnit v2(C) API. Output to speakers works fine but the input from microphone callback is never invoked. The iTerm or Terminal hosts have access according to Settings. The executable also has an embedded info.plist although I do not think this is relevant.

The precise security model is not clear to me, it looks like a major security hole if it worked (anything run from terminal would have access): my guess is that the process launched by an "App" has permissions which then propagate to any child process. However this view is confused by another case where an executable I generate does network access (as it happens only to localhost because it is a regression test) and in this case the executable is asking for network access, not the terminal.

The source code is actually written in Felix which is translated to C++ and then compiled and linked by clang with the -ObjC option so embedded Objective C is supported. The translator is mature enough to have reasonable confidence in its correctness in this kind of simple application. The AudioUnit configuration for the microphone input is:

   // configure
    var outputElement = 0u32;
    var inputElement = 1u32;

    // establish callback
    status = AudioUnitSetProperty(
      outputAudioUnit, 
      kAudioOutputUnitProperty_SetInputCallback,
      kAudioUnitScope_Global,
      inputElement,
      (&inputCallback).address,
      C_hack::sizeof[AURenderCallbackStruct].uint32
    );
    assert noErr == status;

and the inputElement is enabled and outputElement disabled. A second audio unit is constructed later with similar technology which pumps a sine wave to the speakers and that works fine. The actual callback just prints a diagnostic and exits, but the diagnostic is never seen. Originally, the terminal had no permissions, and we guessed the code was correct but failed due to lack of permission to access the microphone. The executable still has no permission but the terminal does now (if I try to run the executable from file manager a terminal pops up).

No errors are reported at any stage. The callback simply isn't invoked.

解决方案

To get a callback, you need to

  1. enable IO
  2. set the audio unit input device

Number 2. trips people up because it's not necessary for output [which sensibly defaults to the default output device], nor is it necessary on iOS, probably because there is no concept of Audio Device there, at least not in the AudioUnit API.

Surprisingly, both these requirements are actually documented! Technote 2091 covers the steps needed to record audio using AudioUnits and code listings 3. and 4. have sample code that enables IO and sets the input device. Listing 4. sets the audio unit input device to whatever the default input device was, but any input device will do.

Since macOS Mojave (10.14), you need an NSMicrophoneUsageDescription string in your Info.plist. Without this, your app is aborted with an exception. With this, the user is shown a prompt requesting permission to access input devices. You can control when this happens using code found here. For a command line tool, you can embed an Info.plist file during the link stage.

On Catalina you also seem to need to opt into audio-input enabled sandboxing or the hardened runtime (or both!). Without one of these your callback is called, but with silence! Both of these runtime environments are enabled using "entitlements" which are metadata that is embedded in your app via codesigning, so you will need some form of codesigning. I don't think this necessarily means you will need a certificate from Apple, there is "local/ad-hoc" code signing, which seems to embed entitlements without a certificate, although I'm not sure how distributable the resulting binaries will be.

这篇关于未调用MacOS Catalina 10.15.7 AudioUnit麦克风通知回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆