You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在AVAudioSession/AVAudioEngine中指定USB音频设备的单声道输入

如何在AVAudioEngine中选择USB音频接口的指定通道并转为单声道播放

我正在开发一款录音应用,使用连接到iPhone的外置USB音频接口(如Focusrite Scarlett Solo)。AVAudioSession.sharedInstance().currentRoute.inputs能正确识别该接口及通道信息,但在AVAudioEngine中将inputNode连接到mainMixerNode时,默认是多声道输入:线路/乐器输入在右声道,麦克风输入在左声道。我需要仅将第2通道(吉他输入)作为单声道信号,在两个扬声器中播放。

试过以下方法但存在问题:

  • 将音频格式通道数改为1:只能获取第一通道的单声道信号,无法选择第2通道
  • 使用通道映射代码:未达到预期效果
  • 附加自定义mixerNode:解决了声道问题,但测试10通道音频接口时仅能传输前两个信号,而GarageBand可正常使用该接口,疑惑苹果的实现方式,且AVAudioSession未提供相关便捷功能。

1. 正确选择指定输入通道并转为单声道

注意:Core Audio中通道索引从0开始,所以第2通道对应索引1。以下两种方法可以实现需求:

方法一:用AVAudioMixerNode配置通道映射

通过自定义混音节点的通道映射规则,直接指定保留目标通道:

let engine = AVAudioEngine()
let inputNode = engine.inputNode
let inputFormat = inputNode.inputFormat(forBus: 0)

// 创建自定义混音节点
let monoMixer = AVAudioMixerNode()
engine.attach(monoMixer)

// 定义单声道输出格式
let monoFormat = AVAudioFormat(commonFormat: inputFormat.commonFormat,
                               sampleRate: inputFormat.sampleRate,
                               channels: 1,
                               interleaved: false)!

// 按原格式连接输入节点到自定义混音,再用单声道格式连接到主混音
engine.connect(inputNode, to: monoMixer, format: inputFormat)
engine.connect(monoMixer, to: engine.mainMixerNode, format: monoFormat)

// 关键:设置输入通道映射,仅保留第2通道(索引1)
if let auMixer = monoMixer.auAudioUnit as? AVAudioUnitMixer {
    // 数组元素为输入通道索引,映射到输出的0号通道
    auMixer.inputChannelMap = [1]
}

do {
    try engine.start()
} catch {
    print("引擎启动失败:\(error)")
}

方法二:在输入回调中直接提取目标通道数据

这种方式更灵活,适合复杂多通道场景:

let engine = AVAudioEngine()
let inputNode = engine.inputNode
let inputFormat = inputNode.inputFormat(forBus: 0)

// 给输入节点安装处理回调
inputNode.installTap(onBus: 0, bufferSize: 1024, format: inputFormat) { buffer, time in
    // 获取第2通道的原始数据
    guard let channelData = buffer.floatChannelData else { return }
    let targetChannelData = channelData[1]
    
    // 创建单声道buffer
    let monoBuffer = AVAudioPCMBuffer(pcmFormat: AVAudioFormat(commonFormat: inputFormat.commonFormat,
                                                               sampleRate: inputFormat.sampleRate,
                                                               channels: 1,
                                                               interleaved: false)!,
                                      frameCapacity: buffer.frameLength)!
    monoBuffer.frameLength = buffer.frameLength
    
    // 把目标通道数据复制到单声道buffer
    memcpy(monoBuffer.floatChannelData?[0], targetChannelData, Int(buffer.frameLength) * MemoryLayout<Float>.stride)
    
    // 将单声道数据传给主混音节点
    engine.mainMixerNode.render(monoBuffer, at: time)
}

do {
    try engine.start()
} catch {
    print("引擎启动失败:\(error)")
}

2. 解决多通道接口仅能使用前两通道的问题

对于10通道这类多通道USB接口,AVAudioEngine默认可能只暴露前两个通道,需要手动配置会话并结合底层API解锁全部通道:

步骤1:配置AVAudioSession支持多通道

let session = AVAudioSession.sharedInstance()
do {
    // 设置会话类别为播放录制,开启多通道支持
    try session.setCategory(.playAndRecord, mode: .default, options: [.mixWithOthers])
    // 强制指定输入输出通道数
    try session.setPreferredInputNumberOfChannels(10)
    try session.setPreferredOutputNumberOfChannels(10)
    try session.activate()
} catch {
    print("会话配置失败:\(error)")
}

步骤2:通过底层AudioUnit获取全部通道

AVAudioEngine的高层封装限制了多通道灵活性,苹果官方应用(如GarageBand)会直接用底层Core Audio API。你可以通过输入节点的底层AudioUnit配置通道数:

if let inputAU = inputNode.auAudioUnit {
    var inputChannels = UInt32(10)
    let status = AudioUnitSetProperty(inputAU,
                                      kAudioUnitProperty_ChannelCount,
                                      kAudioUnitScope_Input,
                                      0,
                                      &inputChannels,
                                      UInt32(MemoryLayout<UInt32>.size))
    if status != noErr {
        print("设置输入通道数失败:\(status)")
    }
}

关于苹果的实现逻辑

GarageBand这类官方应用能完全利用多通道接口,是因为它们直接调用Core Audio的底层HAL(硬件抽象层)API,绕过了AVAudioEngine的高层封装限制。AVAudioEngine为了简化开发做了很多妥协,在多通道场景下灵活性不足,如果需要完全兼容复杂的多通道USB接口,建议结合底层Core Audio API实现。

内容的提问来源于stack exchange,提问作者Kakhi Kiknadze

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 16:22:48