cs guy
cs guy

Reputation: 939

How to play decoded audio data through hardware on IOS?

I have my own sound engine written in C++ and it has some custom abilities. I have the decoded + processed PCM values in my engine but I need to somehow play this through a library on IOS. It works based on a callback system. A 3rd party requests callbacks with given parameters such as numberOfFrames, pointerToFillData etc.

I am very new to IOS Audio and I do not know what gets this job done. On Android Oboe is the lib that does this.

I have found some custom libraries written like novocaine that is very similiar to what I need but its not exactly it. I looked at Core Audio but it seems to me that Core Audio SDK is deprecated. However, Audio Unit that was packed with Core Audio seems like the thing I need.

There are multiple ways to do this. This is why I could really use an example + suggestions on why your way is the preferable way...

Can anyone guide me in the right direction with examples?

I saw @hotpaw2 s answer but I need an example with a reason why his answer is better than other available options.

Upvotes: 4

Views: 382

Answers (2)

Phil Dukhov
Phil Dukhov

Reputation: 87804

You definitely need an AVAudioEngine.

let engine = AVAudioEngine()
let player = AVAudioPlayerNode()
var scheduledFrames: AVAudioFrameCount = 0

init() throws {
    engine.attach(player)
    engine.prepare()
    try engine.start()
}

func addBuffer(buffer: AVAudioPCMBuffer) {
    // this will add the buffer to the end of the queue, read more in the docs
    scheduledFrames += buffer.frameLength
    player.scheduleBuffer(buffer, at: nil) {
        // buffer was played here
        scheduledFrames -= buffer.frameLength
        if scheduledFrames < 44100 { // I used around a second here, calculate depending your format
            // request new buffer
        }
    }
}

you can create an AVAudioPCMBuffer like this:

var data: UnsafeMutablePointer<UnsafeMutablePointer<Float>>!
// fill your data
let count = 100
guard
    let format = AVAudioFormat(
        standardFormatWithSampleRate: 44100,
        channels: 1
    ),
    let buffer = AVAudioPCMBuffer(
        pcmFormat: format,
        frameCapacity: AVAudioChannelCount(count)
    )
else {
    // throw
    return
}
for channel in 0..<Int(format.channelCount) {
    memcpy(buffer.floatChannelData![channel],
           data[channel],
           count * MemoryLayout<Float>.size)
}

Replace floatChannelData to int16ChannelData or int32ChannelData if you need

Upvotes: 3

hotpaw2
hotpaw2

Reputation: 70693

The iOS Audio Queue API is (currently) non-deprecated and callback based.

See: https://developer.apple.com/documentation/audiotoolbox/audio_queue_services

Upvotes: 4

Related Questions