3

I'm trying to connect to Spotify stream and modify the output with custom synthetizer. It would be great to use the awesome AudioKit. In order to alter the output Spotify stream I have to implement this method, which gives me access to the spotify's AUGraph. I can then add AUNodes that will be connected to the input and output of the spotify's graph (it's very nicely described here).

I understand that AudioKit uses CoreAudio internally but I haven't found any way how access the underlying AUNodes for the AKNodes (if there is such a thing). Or whether there is another way how to connect AudioKit AKNode to existing AUGraph.

Now I see that AudioKit uses AVAudioEngine (instead of AUGraph that was used in EZAudio) and I can easily get the output and input nodes. So the real question is whether I can connect AVAudioNode into the AUGraph or whether there is some other way how to convert AVAudioNode to AUNode.

EDIT: I tried to implement Dmitrii suggestion with simple setup like this, trying to modify playback speed:

    var engine: AVAudioEngine = AVAudioEngine()
    var playback = AVAudioUnitVarispeed()


    func connect(outputBus sourceOutputBusNumber: UInt32, ofNode sourceNode: AUNode, toInputBus destinationInputBusNumber: UInt32, ofNode destinationNode: AUNode, inGraph graph: AUGraph, error: NSError?) {

        playback.rate = 0.5

        engine.attach(playback)

        // Connect
        engine.connect(playback, to: engine.mainMixerNode, format: nil)
        try! engine.start()

        var playbackCD = playback.auAudioUnit.componentDescription
        var avPlaybackNode = AUNode()
        try! AUGraphAddNode(graph, &playbackCD, &avPlaybackNode).checkError(message: "Failed to add playback node")

        //Conect source to the mixer input
        AUGraphConnectNodeInput(graph, sourceNode, sourceOutputBusNumber, avPlaybackNode, 0)

        //Connect mixer output to the device output
        AUGraphConnectNodeInput(graph, avPlaybackNode, 0, destinationNode, destinationInputBusNumber)
}

But it does not have any effect on the audio output. It's still coming through though.

Is there some specific lifecycle I should follow when combining AUGraph and the AVAudioEngine? Or am I forgetting something important?

EDIT 2: So I didn't have any luck with adding the node as was suggested, I am not even sure that can work. I had a bit more luck with connecting the nodes with the kAudioUnitProperty_MakeConnection property:

AUGraphNodeInfo(graph, destinationNode, nil, &destinationUnit)

var connection = AudioUnitConnection(sourceAudioUnit: destinationUnit, sourceOutputNumber: 0, destInputNumber: 0)

try! AudioUnitSetProperty(engine.outputNode.audioUnit!, kAudioUnitProperty_MakeConnection, kAudioUnitScope_Input, 0, &connection, UInt32(MemoryLayout<AudioUnitConnection>.size)).checkError(message: "Failed to make connection")

try! engine.start()

This will connect output node of the AVAudioEngine with the output of Spotify. However, if I add any intermediate nodes, it fails to play anything. It's like the AVAudioNodes would not be connected at all:

engine.attach(varispeed)
engine.connect(varispeed, to: engine.mainMixerNode, format: nil)

var connection = AudioUnitConnection(sourceAudioUnit: destinationUnit, sourceOutputNumber: 0, destInputNumber: 0)

try! AudioUnitSetProperty(varispeed.audioUnit, kAudioUnitProperty_MakeConnection, kAudioUnitScope_Input, 0, &connection, UInt32(MemoryLayout<AudioUnitConnection>.size)).checkError(message: "Failed to make connection")

 try! engine.start()

Any idea why this is happening? I would expect the engine output unit to be connected to the main mixer which is connected to the varispeed which is then connected to the output of the spotify. Any help would be greatly appreciated.

Thanks a lot

Tomas

Tomáš Kohout
  • 755
  • 6
  • 15

1 Answers1

1

AVAudioNode has instance property AUAudioUnit. Also, you can get AudioComponentDescription

You can add your node to graph and get AUNode:

AUGraphAddNode(graph,
               yourAudioComponentDescription,
               outAUNode);

EDIT: First, attach nodes, connect them and after that start engine. Show your logs after CAShow(graph) to check your graph.

Dmitrii
  • 85
  • 1
  • 7