0
votes

I am using swift's AVFoundation framework to play some audio. I create an AVAudioSourceNode that will pass some samples to be played.

let srcNode = AVAudioSourceNode { _, timeStamp, frameCount, AudioBufferList -> OSStatus in
        let ablPointer = UnsafeMutableAudioBufferListPointer(AudioBufferList)

}

I then attach this to the audio Engine. and connect it to the mixer.

engine.attach(srcNode)
engine.connect(srcNode, to: engine.mainMixerNode, format:  srcNode.inputFormat(forBus:0))

If I start the engine, the audio plays. However when I delve in deeper, and probe the format of this SourceNode by printing format, the sampleRate is 44,100. The sampleRate of my audio hardware is 48,000.

What I cannot figure out, is that if I have a pre-generated array of samples, to be played at 48kHz. The sourceNode will read this at a speed of 44.1kHz, and then the engine will convert it to 48kHz to be played on my hardware, meaning the actual audio played is longer than the intended original.

How can I actually specify the format of this AVAudioSourceNode so that it works at the same rate? (Again, whilst I can change the format in the engine.connect call, this only changes the connection format, not the rate at which the sourceNode operates.

1

1 Answers

0
votes

There are two answers to this question: (a) How to do it, and (b) why it doesn't work.

(a) How to set the output sample rate for an AVSourceNode

You set the preferred sample rate on the AVAudioSession, not the node.

let audioSession = AVAudioSession.sharedInstance()
let playbackRate = 48_000
do {
    try audioSession.setPreferredSampleRate(playbackRate)
} catch {
    print("Setting PreferredSampleRate to \(playbackRate) failed.")
}

(b) Why it doesn't work

Actually, this does work if targeting macOS or an iOS simulator. If targeting an iOS device (as of 13.4.1) you'll always have 44.1kHz, no matter what. I'm not sure if this a bug or a hardware limitation.