Is .installTap the equivalent of a C callback function?

Expanding a speech to text demo, and while it works, I am still trying to learn Swift. Is .installTap the Swift version of a C callback function?

From what I interpret here, every time the buffer becomes full, the code in between the last { } runs, as well, the code below it is also run.

It almost feels like a callback combined with a GOTO line from basic.

yes, it works, but I'd like to understand that I am getting the flow of the code correctly.

func startSpeechRecognition (){
    let node = audioEngine.inputNode
    let recordingFormat = node.outputFormat(forBus: 0)

    node.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, _) in self.request.append(buffer) }

    audioEngine.prepare()
    do {
        try audioEngine.start()
    } catch let error {
        ...
    }

    guard let myRecognition = SFSpeechRecognizer() else {
        ...          
        return
    }

    if !myRecognition.isAvailable {
        ...
    }


    task = speechRecognizer?.recognitionTask(with: request, resultHandler: { (response, error) in guard let response = response else {
        if error != nil {
            print ("\(String(describing: error.debugDescription))")
        } else {
            print ("problem in repsonse")
        }
        return
    }
    let message = response.bestTranscription.formattedString
        
    print ("\(message)")
        
    })
}
Answered by Claude31 in 699908022

Yes.

Doc explains:

tapBlock

A block the framework calls with audio buffers.

Which means that the closure (block) is called repeatedly as soon as the node gets an audio buffer. It plays as an observer, running permanently until you stop it. And code execution continues in sequence as soon tap is created.

Doc also reminds:

The framework may invoke the tapBlock on a thread other than the main thread.

Is .installTap the Swift version of a C callback function?

What do you mean exactly ? What is the problem (if any).

Why do you think installTap is a call back ? It is simply a func that uses a closure as argument (closure here aka callback), but here you define inline, not call an external one (which you could).

This discussion may give you details. https://stackoverflow.com/questions/36500109/whats-the-difference-between-closures-and-callbacks-in-swift

No, there is no error, it's the flow I am trying to understand.

The code block in-between the last { } get's called multiple times , when the buffer is full I assume, and then the code continues to run everything below it as well.

Accepted Answer

Yes.

Doc explains:

tapBlock

A block the framework calls with audio buffers.

Which means that the closure (block) is called repeatedly as soon as the node gets an audio buffer. It plays as an observer, running permanently until you stop it. And code execution continues in sequence as soon tap is created.

Doc also reminds:

The framework may invoke the tapBlock on a thread other than the main thread.

I'm glad I asked this, but it turns out I do NOT understand the flow. How is

task = speechRecognizer?.recognitionTask(with: request, resultHandler: { (response, error) in guard let response = response else {

always being called multiple times? Does it have a connection to node.installTap?

This is a rewriting of my original question, once I realized I was reading the flow incorrectly.

Working on a speech to text demo, which works. But I am still trying to learn the flow of Swift. While I may be calling it incorrectly, I'm looking at the closure in node.installTap as a C callback function. When the buffer is full, the code within the closure is called.

From what I interpret here, every time the buffer becomes full, the closure from within the node.installTap runs.

What I can't figure out is what triggers the closure within:

task = speechRecognizer?.recognitionTask(with: request, resultHandler: {})

The entire demo below works, am just trying to figure out how the AVAudioEngine knows when to call that second closure. Is there some connection?

func startSpeechRecognition (){
    let node = audioEngine.inputNode
    let recordingFormat = node.outputFormat(forBus: 0)

    node.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) 
    { (buffer, _) in self.request.append(buffer) }

    audioEngine.prepare()
    do {
        try audioEngine.start()
    } catch let error {
        ...
    }

    guard let myRecognition = SFSpeechRecognizer() else {
        ...          
        return
    }

    if !myRecognition.isAvailable {
        ...
    }


    task = speechRecognizer?.recognitionTask(with: request, resultHandler: 
    { (response, error) in guard let response = response else {
        if error != nil {
            print ("\(String(describing: error.debugDescription))")
        } else {
            print ("problem in repsonse")
        }
        return
    }
    let message = response.bestTranscription.formattedString
        
    print ("\(message)")
        
    })
}
Is .installTap the equivalent of a C callback function?
 
 
Q