【问题标题】:How to play sound to a specific output channel on a USB audio interface?如何在 USB 音频接口上将声音播放到特定输出通道?
【发布时间】:2018-04-06 22:28:13
【问题描述】:

我有一个 motu UltraLite mk4 USB 音频接口连接到运行 MacOS 10.13.3 的 Mac。

我正在尝试播放三个立体声文件,每个文件都有自己的立体声扬声器。

为了降低复杂性,我只是试图让一个 AVAudioPlayerNode 的立体声从默认输出通道 0 和 1 以外的其他东西中发出。

USB audio interface front

USB audio interface back

我希望通过 AVAudioEngine + 一些低级核心音频来实现这一点。

到目前为止,通过配置 AVAudioEngine 的输出节点,我已经成功地将音频播放到我的 USB 音频接口:

AudioUnit audioUnit = [[self.avAudioEngine outputNode] audioUnit];
OSStatus error = AudioUnitSetProperty(audioUnit,
    kAudioOutputUnitProperty_CurrentDevice,
    kAudioUnitScope_Global,
    0,
    &deviceID,
    sizeof(deviceID));
if (error) {
    NSLog(@"Failed to set desired output audio device: %d", (int)
}

我还成功地设置了一个通道映射,让一个播放器可以在我的 USB 音频接口 as described by theanalogkid in Apple's dev forums 的通道 4+5 上播放立体声文件。

频道映射的问题在于它被全局应用于 AVAudioEngine 的输出,并且它会影响所有 AVAudioPlayerNodes。所以这不是解决方案。

因此,我没有在 AVAudioEngine 的 outputNode 的 AudioUnit 上使用该通道映射,而是尝试创建一个具有自定义通道布局的 AVAudioFormat,该布局指定离散通道索引 4 和 5:

// Create audio channel layout struct with two channels
int numChannels = 2;
AudioChannelLayout *audioChannelLayout = calloc(1, sizeof(AudioChannelLayout) + (numChannels - 1) * sizeof(AudioChannelDescription));
audioChannelLayout->mNumberChannelDescriptions = numChannels;
audioChannelLayout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
audioChannelLayout->mChannelBitmap = 0;

// Configure channel descriptions
audioChannelLayout->mChannelDescriptions[0].mChannelFlags = kAudioChannelFlags_AllOff;
audioChannelLayout->mChannelDescriptions[0].mChannelLabel = kAudioChannelLabel_Discrete_4;
audioChannelLayout->mChannelDescriptions[0].mCoordinates[0] = 0;
audioChannelLayout->mChannelDescriptions[0].mCoordinates[1] = 0;
audioChannelLayout->mChannelDescriptions[0].mCoordinates[2] = 0;

audioChannelLayout->mChannelDescriptions[1].mChannelFlags = kAudioChannelFlags_AllOff;
audioChannelLayout->mChannelDescriptions[1].mChannelLabel = kAudioChannelLabel_Discrete_5;
audioChannelLayout->mChannelDescriptions[1].mCoordinates[0] = 0;
audioChannelLayout->mChannelDescriptions[1].mCoordinates[1] = 0;
audioChannelLayout->mChannelDescriptions[1].mCoordinates[2] = 0;

// Create AVAudioChannelLayout
AVAudioChannelLayout *avAudioChannelLayout = [[AVAudioChannelLayout alloc] initWithLayout:audioChannelLayout];

// Create AVAudioFormat
AVAudioOutputNode *outputNode = engine.avAudioEngine.outputNode;
AVAudioFormat *outputHWFormat = [outputNode outputFormatForBus:0];
AVAudioFormat *targetFormat = [[AVAudioFormat alloc] initWithStreamDescription:player.avAudioFile.processingFormat.streamDescription
                                                                 channelLayout:avAudioChannelLayout];

然后我将播放器的混音器连接到引擎的主混音器,使用输出硬件格式:

[engine connect:speakerMixer to:[engine mainMixerNode] format:outputHWFormat];

播放器到它的混音器,使用经过调整的通道布局的自定义 AVAudioFormat:

[engine connect:player to:speakerMixer format:targetFormat];

结果?声音播放,但仍只出 USB 音频接口默认的 0 和 1 声道。

如果我将 targetFormat 应用到混音器到 mainMixer 的连接,USB 音频接口根本听不到声音。

我还尝试将通道映射应用到 AVAudioMixerNode 的底层 AVAudioUnit,但是我似乎无法从 AVAudioUnit 获取底层裸机 AudioUnit 以应用通道映射。也许这对于 AVAudioEngine 是不可能的。如果是这样,您是否知道有其他方法可以做到这一点?

可能我忽略了一些重要的事情。我花了很多天研究这个,感觉卡住了。感谢我能得到的任何帮助。

【问题讨论】:

  • 我认为您需要在输出节点 AudioUnit 上设置总线 0 输入范围 kAudioUnitProperty_StreamFormat 来描述您的 6 个(对吗?)通道。不确定AVAudioEngine 是否会对此感到满意。如果没有,您可以切换到 CoreAudio。这似乎与链接的帖子不一致,尽管它指的是 iOS 多路由 AudioSession 类别,它可能会为您执行此步骤。
  • @RhythmicFistman 输出通道的索引从 0 到 19,前 8 个按离散顺序路由到 USB 音频接口的模拟输出。当我将通道映射应用于 outputNode 的底层 AudioUnit 时,它可以工作。如果您在全局范围内应用该格式,您将如何让各个播放器节点或混音器节点将其音频路由到特定通道?
  • 这个我不知道。连接节点时可以使用总线参数吗?

标签: audio avfoundation core-audio avaudioengine avaudioplayernode


【解决方案1】:

多年前,AVAudioEngine 的文档中有一条警告,即应用程序应该只有一个实例。

显然,这个限制消失了,我已经成功创建了多个实例,每个实例都有自己的通道映射应用于引擎的 outputNode 的 AudioUnit。

文档仍然声称引擎的 outputNode 是“单例”,尽管我在 Mac 上的测试表明每个 AVAudioEngine 实例都有自己的输出节点实例,并且可以在一个实例上设置通道映射而不影响另一个的输出。

这并不是我一直在寻找的,尽管它似乎确实有效。我仍然更喜欢一种解决方案,它可以将通道从播放器或混音器节点路由到音频硬件的特定输出通道,并使用一个 AVAudioEngine 实例完成所有操作。另一方面,现在我很难找到一个很好的理由来说明运行多个 AVAudioEngine 实例会很糟糕。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-13
    • 2012-06-13
    • 2017-05-20
    • 1970-01-01
    • 1970-01-01
    • 2017-10-04
    • 2020-08-22
    相关资源
    最近更新 更多