使用AVFoundation和Swift

时间:2016-07-26 23:55:00

标签: swift macos audio avfoundation avplayer

如何使用AVFoundation访问1-2以外的其他音频硬件输出?我正在为Mac OS-X应用程序编写快速代码,该应用程序通过各种输出设备(USB接口,dante,soundflower)播放mp3文件,如下所示:

myPlayer = AVPlayer(URL: myFilePathURL)
myPlayer.audioOutputDeviceUniqueID = myAudioOutputDevices[1].deviceUID()
myPlayer.play()

但是,我不确定如何将音频文件播放到1-2以外的频道。例如,我想播放一个mp3输出3-4。

我可以通过AVPlayer执行此操作吗?或者我需要到别处寻找?也许AVAudioEngine和调音台节点一起?我浏览了AVAudioEngine示例,无法找到任何地方引用的硬件通道。谢谢你的帮助!

2 个答案:

答案 0 :(得分:1)

我有一个快速版本,使用2个频道设置频道映射属性。我没有使用完整的多声道系统进行测试,但原则应该是相同的。

let engine = AVAudioEngine()
let player = AVAudioPlayerNode()

func testCode(){

    // get output hardware format
    let output = engine.outputNode
    let outputHWFormat = output.outputFormatForBus(0)
    // connect mixer to output
    let mixer = engine.mainMixerNode
    engine.connect(mixer, to: output, format: outputHWFormat)


    //then work on the player end by first attaching the player to the engine
    engine.attachNode(player)


    //find the audiofile
    guard let audioFileURL = NSBundle.mainBundle().URLForResource("tones", withExtension: "wav") else {
        fatalError("audio file is not in bundle.")
    }


    var songFile:AVAudioFile?
    do {
        songFile = try AVAudioFile(forReading: audioFileURL)
        print(songFile!.processingFormat)

        // connect player to mixer
        engine.connect(player, to: mixer, format: songFile!.processingFormat)

    } catch {
        fatalError("canot create AVAudioFile \(error)")
    }



    let channelMap: [Int32] = [0, 1] //left out left, right out right
    //let channelMap: [Int32] = [1, 0] //right out left, left out right


    let propSize: UInt32 = UInt32(channelMap.count) * UInt32(sizeof(sint32))

    let code: OSStatus = AudioUnitSetProperty((engine.inputNode?.audioUnit)!,
                                              kAudioOutputUnitProperty_ChannelMap,
                                              kAudioUnitScope_Global,
                                              1,
                                              channelMap,
                                              propSize);

    print(code)


    do {
        try engine.start()
    } catch {
        fatalError("Could not start engine. error: \(error).")
    }

    player.scheduleFile(songFile!, atTime: nil) {
        print("done")
        self.player.play()
    }

    player.play()



}

答案 1 :(得分:1)

我随着时间的推移迭代了这段代码 - 但基本的大纲会起作用。这是我当前的设置代码,用于将音频发送到多通道设置。我目前正在使用带有16个立体声实例流的Dante Virtual Soundcard使用以下代码执行此操作:

func setupAudioPath(){
    //print("setupAudioPath")

    // get output hardware format
    let output = engine.outputNode
    outputHWFormat = output.outputFormat(forBus: 0)

    //print("outputHWFormat = \(outputHWFormat)")
    //print("outputHWFormat.channelCount = \(outputHWFormat.channelCount)")

    // connect mixer to output
    mixer = engine.mainMixerNode

    //then work on the player end by first attaching the player to the engine
    engine.attach(player)

    engine.connect(mixer, to: output, format: outputHWFormat)

    var channelMap: [sint32] = []
    //UInt32 numOfChannels = fileFormat.NumberChannels();
    let numOfChannels: UInt32 = UInt32(numberOfStreams) * UInt32(2);    // Number of output device channels
    let mapSize: UInt32 = numOfChannels * UInt32(MemoryLayout<sint32>.size);
    for _ in 0...(numOfChannels-1) {
        channelMap.append(-1)
    }
    //channelMap[desiredInputChannel] = deviceOutputChannel;
    channelMap[leftChannel - 1] = 0;
    channelMap[leftChannel]     = 1;


    //print(channelMap)
    //print("number of channels in my map: \(channelMap.count)")

    let code: OSStatus = AudioUnitSetProperty((engine.outputNode.audioUnit)!,
                                              kAudioOutputUnitProperty_ChannelMap,
                                              kAudioUnitScope_Global,
                                              1,
                                              channelMap,
                                              mapSize);


    print("osstatus = \(code)")
}