如何在 Mojave/Catalina 下从后台(基于launchctl)进程录制音频?

Jer*_*ner 5 macos core-audio launchctl privacy-policy macos-catalina

首先,一些背景信息来解释我的动机:我有一个 Qt/C++/Objective-C++ 应用程序,它使用 CoreAudio/AVFoundation 从 Mac 上的指定音频输入接收传入的音频,修改音频,然后播放修改后的音频音频通过某些指定的音频输出返回。在 Mojave 和 Catalina 之前,这一切都很好,此时 Apple 的新麦克风隐私限制导致它无法再接收传入的音频(由于缺乏明确的用户使用权限,它只接收零/静音麦克风)。

为了解决这个问题,我通过新获取最user's-允许添加的代码来跳火圈(即加了NSMicrophoneUsageDescription标签Info.plist中,加入电话authorizationStatusForMediaTyperequestAccessForMediaType建议作为,等等),现在我的应用程序再次工作当预期从它的图标启动(即它提出“MyAudioProcessingApp 想要使用麦克风”请求者,一旦用户响应,我的应用程序的复选框就会出现在“安全和隐私/隐私/麦克风”控制面板中,并控制是否或不是我的应用程序可以收听传入的音频)。就目前而言,这一切正常。

我的问题是——我的应用程序还有一个“后台模式”功能,用户可以要求应用程序将自身安装为非 GUI 系统服务(它在启动时通过 launchd/launchctl 运行),这样它就会Mac 一启动就在后台进行音频处理(即不需要任何人登录或手动启动应用程序)。对于想要在“无头/嵌入式”mac 上运行此应用程序作为固定音频安装的一部分的人来说,这非常有用,任何人都需要做的就是打开 Mac 以使其开始处理音频。

但是,我发现当我的应用程序以这种方式作为后台进程运行时,[AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio]总是返回AVAuthorizationStatusDenied,即使用户之前已授予我的应用程序访问麦克风的权限。即使进程的有效用户 ID 与授予麦克风权限的用户相同,并且运行的可执行文件与先前生成用户同意的权限提示的文件相同,也会发生这种情况。

我的问题是,在后台运行时是否需要一些特殊技巧才能访问麦克风?或者 Apple 是否认为 launchctl-launched-daemons 在任何情况下都无法访问麦克风,因此我很不走运?

ps 我的应用程序的MyAudioProcessingApp.app/Contents/Info.plist文件和/Library/LaunchDaemons/com.mycompany.myprogram.plist文件(都略微匿名)如下,以防它们相关:

----- begin MyProcessingApp.app/Contents/Info.plist ------- snip ------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>CFBundleExecutable</key>
        <string>MyAudioProcessingApp</string>
        <key>CFBundleGetInfoString</key>
        <string>Created by Qt/QMake</string>
        <key>CFBundleIconFile</key>
        <string>vcore.icns</string>
        <key>CFBundleIdentifier</key>
        <string>com.mycompany.MyAudioProcessingApp</string>
        <key>CFBundlePackageType</key>
        <string>APPL</string>
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>LSMinimumSystemVersion</key>
        <string>10.10</string>
        <key>NOTE</key>
        <string>This file was generated by Qt/QMake.</string>
        <key>NSMicrophoneUsageDescription</key>
        <string>To allow MyAudioProcessingApp to process incoming audio data.</string>
        <key>NSPrincipalClass</key>
        <string>NSApplication</string>
        <key>NSSupportsAutomaticGraphicsSwitching</key>
        <true/>
</dict>
</plist>
----- end MyProcessingApp.app/Contents/Info.plist ------- snip ------

---- begin /Library/LaunchDaemons/com.mycompany.myprogram.plist   ------ snip ------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "
http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>EnvironmentVariables</key>
    <dict>
      <key>PATH</key>
      <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:</string>
    </dict>
    <key>Label</key>
    <string>com.mycompany.MyAudioProcessingApp</string>
    <key>Program</key>
    <string>/Library/MyCompany/MyAudioProcessingApp/run_my_program_in_background.sh</string>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>StandardOutPath</key>
    <string>/tmp/myprogram.stdout</string>
    <key>StandardErrorPath</key>
    <string>/tmp/myprogram.stderr</string>
    <key>UserName</key>
    <string>jaf</string>      // NOTE: this is set dynamically to the correct user as part of the install-as-service step
    <key>ProcessType</key>
    <string>Interactive</string>
    <key>GroupName</key>
    <string>admin</string>
    <key>InitGroups</key>
    <true/>
  </dict>
</plist>
---- end /Library/LaunchDaemons/com.mycompany.myprogram.plist   ------ snip ------

---- begin /Library/MyCompany/MyAudioProcessingApp/run_my_program_in_background.sh   ------ snip ------
#!/bin/bash
PATH_TO_MYPROGRAM_EXE="/Library/MyCompany/MyAudioProcessingApp/MyAudioProcessingApp.app/Contents/MacOS/MyAudioProcessingApp"
"$PATH_TO_MYPROGRAM_EXE" run_without_gui
exit 0
---- end /Library/MyCompany/MyAudioProcessingApp/run_my_program_in_background.sh   ------ snip ------
Run Code Online (Sandbox Code Playgroud)

Jer*_*ner 3

今天早上我收到了苹果技术支持人员的回复;他们说不可能从非 GUI 系统服务访问麦克风。

他们建议使用反馈助手提交功能请求(我已经这样做了),或者作为解决方法,将我的程序设置为登录项,并将 Mac 设置为自动登录该用户。

由于我不太相信苹果会根据我的要求改变他们的行为,我想后者是我接下来要研究的。