USB microphone with high samplerate and AVAudioEngine

Hello,

I can't get my head wrapped around the following problem:

I have an external USB microphone capable of samplerates of up to 500 kHz. I want to capture the samples and do analysis and display - no playback required. I can not find a way to run the microphone with its maximum samplerate, I always get 48 kHz.

I would like to stick to AVAudioEngine if possible.

Any pointer welcome.

thx! volker

Answered by Engineer in 788993022

On iOS you can call setPreferredSampleRate(_:) then check whether the requested change took effect.

On macOS you can get the ID of the underlying Core Audio device from an AVAudioIONode, and get and set the device's sample rate using the kAudioDevicePropertyNominalSampleRate selector. You can similarly get a list of sample rates the device supports using the kAudioDevicePropertyAvailableNominalSampleRates selector. Below is an example:

// initialize the input node and store the device ID
let inputNode = engine.inputNode
let device = inputNode.auAudioUnit.deviceID

// get the list of available sample rates
var address = AudioObjectPropertyAddress()
address.mSelector = kAudioDevicePropertyAvailableNominalSampleRates
address.mScope = kAudioObjectPropertyScopeGlobal
address.mElement = kAudioObjectPropertyElementMain

var size = UInt32.zero
assert(AudioObjectGetPropertyDataSize(device, &address, 0, nil, &size) == noErr)

let count = size / UInt32(MemoryLayout<AudioValueRange>.stride)
var valueRanges = [AudioValueRange](repeating: .init(), count: Int(count))
assert(AudioObjectGetPropertyData(device, &address, 0, nil, &size, &valueRanges) == noErr)

// print the available sample rates
for valueRange in valueRanges {
    print(valueRange.mMaximum)
}

// set the sample rate
address.mSelector = kAudioDevicePropertyNominalSampleRate
size = UInt32(MemoryLayout<Double>.stride)

var sampleRate = valueRanges.last?.mMaximum ?? 48000.0
assert(AudioObjectSetPropertyData(device, &address, 0, nil, size, &sampleRate) == noErr)

// get the current sample rate and print it
assert(AudioObjectGetPropertyData(device, &address, 0, nil, &size, &sampleRate) == noErr)
print(sampleRate)

try? engine.start()

On iOS you can call setPreferredSampleRate(_:) then check whether the requested change took effect.

On macOS you can get the ID of the underlying Core Audio device from an AVAudioIONode, and get and set the device's sample rate using the kAudioDevicePropertyNominalSampleRate selector. You can similarly get a list of sample rates the device supports using the kAudioDevicePropertyAvailableNominalSampleRates selector. Below is an example:

// initialize the input node and store the device ID
let inputNode = engine.inputNode
let device = inputNode.auAudioUnit.deviceID

// get the list of available sample rates
var address = AudioObjectPropertyAddress()
address.mSelector = kAudioDevicePropertyAvailableNominalSampleRates
address.mScope = kAudioObjectPropertyScopeGlobal
address.mElement = kAudioObjectPropertyElementMain

var size = UInt32.zero
assert(AudioObjectGetPropertyDataSize(device, &address, 0, nil, &size) == noErr)

let count = size / UInt32(MemoryLayout<AudioValueRange>.stride)
var valueRanges = [AudioValueRange](repeating: .init(), count: Int(count))
assert(AudioObjectGetPropertyData(device, &address, 0, nil, &size, &valueRanges) == noErr)

// print the available sample rates
for valueRange in valueRanges {
    print(valueRange.mMaximum)
}

// set the sample rate
address.mSelector = kAudioDevicePropertyNominalSampleRate
size = UInt32(MemoryLayout<Double>.stride)

var sampleRate = valueRanges.last?.mMaximum ?? 48000.0
assert(AudioObjectSetPropertyData(device, &address, 0, nil, size, &sampleRate) == noErr)

// get the current sample rate and print it
assert(AudioObjectGetPropertyData(device, &address, 0, nil, &size, &sampleRate) == noErr)
print(sampleRate)

try? engine.start()

The reply from Engineer got me on the track for macOS. It seems even so the input device is correctly selected in system preferences and is returned as current input device, the AVAudioEngine inputNode uses a different device id. Now when manually setting the inputNode AUAudioUnit id to the wanted input device ( code taken from a reply here: https://forums.developer.apple.com/forums/thread/71008 ), i can tap the USB microphone and analyse its input data.

So while the above reply does not solve the question, it gave the right hint and put me on track quickly.

USB microphone with high samplerate and AVAudioEngine
 
 
Q