5

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

为了解决这个问题,我添加了代码以跳过新的 get-the-user's-permission(即向 Info.plist 添加标签,添加对和的NSMicrophoneUsageDescription调用等),现在我的应用程序再次按预期工作从其图标启动(即它提出“MyAudioProcessingApp 想使用麦克风”请求程序,一旦用户响应,我的应用程序的复选框就会出现在“安全和隐私/隐私/麦克风”控制面板中,并控制是否不是我的应用程序可以收听传入的音频)。就目前而言,这一切都很好。authorizationStatusForMediaTyperequestAccessForMediaType

我的问题是——我的应用程序还有一个“后台模式”功能,用户可以要求应用程序将自身安装为非 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 ------
4

2 回答 2

2

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

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

由于我对 Apple 会根据我的要求改变他们的行为没有很大的信心,我想后者是我接下来要研究的。

于 2019-10-07T18:22:18.113 回答
0

您可以尝试将您的作业定义 .plist 移动到 /System/Library/LaunchDaemons/ 并从那里尝试删除 UserName 键。

毕竟,它可能允许系统守护进程限制较少的访问,毕竟,使用语音控制 mac 的人如何登录。可能会问苹果技术支持,或者可能是包容副总裁。

您可能需要暂时禁用 SIP 才能将其放入其中。还记得先使用 launchctl 删除现有作业。

不太可能,但如果您目前没有选择,仍然值得一试,也可以从 /System/Library/LaunchAgents/ 再次尝试,无论是否使用 UserName 键

于 2019-10-04T03:42:51.117 回答