hi,
Is there an Audio Unit logo I can show on my website? I would love to show that my application is able to host Audio Unit plugins.
regards, Joël
Audio
RSS for tagDive into the technical aspects of audio on your device, including codecs, format support, and customization options.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I want the audio session to always use the built-in microphone. However, when using the setPreferredInput() method like in this example
private func enableBuiltInMic() {
// Get the shared audio session.
let session = AVAudioSession.sharedInstance()
// Find the built-in microphone input.
guard let availableInputs = session.availableInputs,
let builtInMicInput = availableInputs.first(where: { $0.portType == .builtInMic }) else {
print("The device must have a built-in microphone.")
return
}
// Make the built-in microphone input the preferred input.
do {
try session.setPreferredInput(builtInMicInput)
} catch {
print("Unable to set the built-in mic as the preferred input.")
}
}
and calling that function once in the initializer,
the audio session still switches to the external microphone once one is plugged in.
The session's preferredInput is nil again at that point, even if the built-in microphone is still listed in availableInputs.
So,
why is the preferredInput suddenly reset?
when would be the appropriate time to set the preferredInput again?
Observing the session’s availableInputs did not work and setting the preferredInput again in the routeChangeNotification handler seems a bad choice as it’s already a bit too late then.
Hello,
I'm trying to determine the best/recommended AVAudioSession configuration (i.e category, mode, and options) for the following use-case.
Essentially, I'd like to switch between periods of playing an audio file and then recognizing speech. The audio file is typically speech and I don't intend for playback and speech recognition to occur simultaneously. I'd like for the user to sill be able to interact with Siri and I'd like for it to work with CarPlay where navigation prompts can occur.
I would assume the category to use is 'playAndRecord', but I'm not sure if it's better to just set that once for the entire lifecycle, or set to 'playback' for audio file playback and then switch to 'playAndRecord' for speech recognition . I'm also not sure on the best 'mode' and 'options' to set. Any suggestions would be appreciated.
Thanks.
I’m seeing what appears to be an iOS audio-session issue that occurs only when a phone call happens while the app is in the background.
API: AVAudioSession, AVAudioRecorder
Background Modes: Audio enabled (UIBackgroundModes = audio)
Category: .playAndRecord
Microphone permission: granted
Expected Behavior
If the app is recording audio in the background and a phone call interrupts it:
AVAudioSession.interruptionNotification(.began) fires
Call ends
AVAudioSession.interruptionNotification(.ended) fires
App should be able to re-activate its audio session and resume or restart recording
Apple documentation suggests this should be supported for background audio apps.
Actual Behavior
When the app is in the background and phone call is ended:
AVAudioSession.interruptionNotification(.ended) does fire
Attempting to reactivate the audio session always fails:
Error Domain=NSOSStatusErrorDomain
Code=560557684 ("!int")
"Session activation failed"
The session appears to remain permanently “interrupted”
Retrying activation (with delays) does not help
Recreating AVAudioRecorder does not help
Reactivation works only after the app is opened again
ApplicationMusicPlayer is not available on watchOS but all other platforms. Is there a technical reason for that like battery life? Same goes for SystemMusicPlayer and MPMusicPlayerController. I already filed feedbacks for that.
Is it possible to find IDR frame (CMSampleBuffer) in AVAsset h264 video file?
I have some tried-and-tested code that records and plays back audio via AUHAL which breaks on Tahoe on Intel. The same code works fine on Sequioa and also works on Tahoe on Apple Silicon.
To start with something simple, the following code to request access to the Microphone doesn't work as it should:
bool RequestMicrophoneAccess ()
{
__block AVAuthorizationStatus status =
[AVCaptureDevice authorizationStatusForMediaType: AVMediaTypeAudio];
if (status == AVAuthorizationStatusAuthorized)
return true;
__block bool done = false;
[AVCaptureDevice requestAccessForMediaType: AVMediaTypeAudio completionHandler: ^ (BOOL granted)
{
status = (granted) ? AVAuthorizationStatusAuthorized : AVAuthorizationStatusDenied;
done = true;
}];
while (!done)
CFRunLoopRunInMode (kCFRunLoopDefaultMode, 2.0, true);
return status == AVAuthorizationStatusAuthorized;
}
On Tahoe on Intel, the code runs to completion but granted is always returned as NO. Tellingly, the popup to ask the user to grant microphone access is never displayed, even though the app is not present in the Privacy pane and never appears there. On Apple Silicon, everything works fine.
There are some other problems, but I'm hoping they have a common underlying cause and that the Apple guys can figure out what's wrong from the information in this post. I'd be happy to test any potential fix. Thanks.
Topic:
Media Technologies
SubTopic:
Audio
Among Japanese end users, audio issues during screen recording—primarily in game applications—have become a topic of discussion.
We have confirmed that the trigger for this issue is highly likely to be related to changes to IOBufferDuration.
When using setPreferredIOBufferDuration and the IOBufferDuration is set to a value smaller than the default, audio problems occur in the recorded screen capture video.
Audio playback is performed using AudioUnit (RemoteIO).
https://developer.apple.com/documentation/avfaudio/avaudiosession/setpreferrediobufferduration(_:)?language=objc
This issue was not observed on iOS 18, and it appears to have started occurring after upgrading to iOS 26.
We provide an audio middleware solution, and we had incorporated changes to IOBufferDuration into our product to achieve low-latency audio playback.
As a result, developers using our product as well as their end users are being affected by this issue.
We kindly request that this issue be investigated and addressed in a future update.
“This document has been translated by AI. The original text is included below for reference.”
日本のエンドユーザー間で主にゲームアプリケーションにおける画面収録時の音声の問題が話題になっています。
こちらの症状のトリガーが、IOBufferDurationの変更によるものである可能性が高いことを確認しました。
setPreferredIOBufferDurationを使用し、IOBufferDurationがデフォルトより小さい状態の時、画面収録された動画の音声に問題が発生することをしています。
音声の再生にはAudioUnit(RemoteIO)を使用しています。
https://developer.apple.com/documentation/avfaudio/avaudiosession/setpreferrediobufferduration(_:)?language=objc
iOS 18ではこのような問題は確認されておらず、iOS26になってから問題が発生しているようです。
私たちはオーディオミドルウェアを提供しており、低遅延の再生のためにIOBufferDurationの変更を製品に組み込んでいました。
そのため、弊社製品をご利用いただいている開発者およびエンドユーザーの皆様がこの不具合の影響を受けています。
こちらの不具合の調査及び修正対応を検討いただけますでしょうか。
Topic:
Media Technologies
SubTopic:
Audio
Is there a way to destroy MIDIUMPMutableEndpoint again?
In my app, the user has a setting to enable and disable MIDI 2.0. If MIDI 2.0 should not be supported (or if iOS version < 18), it creates a virtual destination and a virtual source. And if MIDI 2.0 should be enabled, it instead creates a MIDIUMPMutableEndpoint, which itself creates the virtual destination and source automatically.
So here is my problem: I didn't find any way to destroy the MIDIUMPMutableEndpoint again. There is a method to disable it (setEnabled:NO), but that doesn't destroy or hide the virtual destination and source. So when the user turns MIDI 2.0 support off, I will have two virtual destinations and sources, and cannot get rid of the 2.0 ones.
What is the correct way to get rid of the MIDIUMPMutableEndpoint once it is created?
Hello,
I need to know what is a unique identifier of a MIDI device (source/destination). Important note: I want to get the same ID when a device is reconnected (unplugged and then plugged again).
The main candidate is kMIDIPropertyUniqueID property. But I don't know if it meets the requirement above or not. Additional question: is it always available for any endpoint?
Also there is kMIDIPropertyDeviceID property. What about it?
And one more option is just MIDIEndpointRef returned by MIDIGetSource or MIDIGetDestination.
So what is the proper way to get ID which persists between device reconnections?
Environment→ ・Device: iPad 10th generation ・OS:**iOS18.3.2
We're using AVAudioPlayer to play a sound when a button is tapped. In our use case, this button can be tapped very frequently — roughly every 0.1 to 0.2 seconds. Each tap triggers the following function:
var audioPlayer: AVAudioPlayer?
func soundPlay(resource: String, type: String){
guard let path = Bundle.main.path(forResource: resource, ofType: type) else {
return
}
do {
audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
audioPlayer!.delegate = self
try audioSession.setCategory(.playback)
} catch {
return
}
self.audioPlayer!.play()
}
The issue is that under high-frequency tapping (especially around 0.1–0.15s intervals), the app occasionally crashes. The crash does not occur every time, but it happens randomly — sometimes within 30 seconds, within 1 minute, or even 3 minutes of continuous tapping.
Interestingly, adding a delay of 0.2 seconds between button taps seems to prevent the crash entirely. Delays shorter than 0.2 seconds (e.g.,0.15s,0.18s) still result in occasional crashes.
My questions are:
**Is this expected behavior from AVAudioPlayer or AVAudioSession?
Could this be a known issue or a limitation in AVFoundation?
Is there any documentation or guidance on handling frequent sound playback safely?**
Any insights or recommendations on how to handle rapid, repeated audio playback more reliably would be appreciated.
I’m facing a strange audio routing issue that seems specific to iPhone 14 Pro / Pro Max.
I’m using LiveKit (WebRTC) in a React Native app, which uses AVAudioSession internally for audio capture (VoIP / call-style usage).
🔍 What’s happening:
I’m using an external USB microphone.
On these devices:
iPhone 11 → ✅ USB mic works
iPhone 13 → ✅ USB mic works
iPhone 17 Pro → ✅ USB mic works
iPhone 14 Pro Max → ❌ USB mic does NOT work
On iPhone 14 Pro Max:
The same USB mic:
✅ Works in Voice Memos
✅ Works in Instagram Live
❌ Does NOT appear as an input option in my app
❌ Does NOT work in WhatsApp / Instagram calls
Also:
In my app on iPhone 14 Pro Max, iOS does not show the audio input selector UI
On iPhone 17 Pro, the same app and same build does show the selector and the USB mic works
⚙️ My audio session config ( LiveKit ):
await AudioSession.setAppleAudioConfiguration({
audioCategory: 'playAndRecord',
audioMode: 'default',
audioCategoryOptions: ['allowBluetooth', 'defaultToSpeaker'],
});
await AudioSession.startAudioSession();
❓ My questions:
Is this a known limitation or behavior specific to iPhone 14 Pro / Pro Max?
Does iPhone 14 Pro have different audio routing rules for call / VoIP mode compared to other devices?
Why does the same USB mic work in recording apps (Voice Memos, Instagram Live) but not in call-style apps (LiveKit, WhatsApp, Instagram call)?
Is there any documented difference in AVAudioSession behavior on iPhone 14 Pro regarding external USB audio inputs?
In iOS 18, CarPlay shows an error: “There was a problem loading this content” after playback starts. Audio works fine, but the Now Playing screen doesn’t load. I’m using MPPlayableContentManager. This worked fine in iOS 17. Anyone else seeing this error in iOS 18?
This is the code I use:
@MainActor func picker()->UIViewController{
let pickerController = MPMediaPickerController(mediaTypes: .music)
print(pickerController)
pickerController.showsCloudItems=true
pickerController.prompt = NSLocalizedString("Add pieces to queue", comment:"");
pickerController.allowsPickingMultipleItems=true;
pickerController.delegate=MPMusicPlayerControllerSingleton.sharedController();
return pickerController
}
MainActor
@IBAction func handleBrowserTapped(_ sender: AnyObject){
if let pickerController=contentProvider?.picker(){
self.present(pickerController, animated:true, completion:nil)
}
}
And this his is the crash log:
*** Assertion failure in -[MPMediaPickerController_Appex requestRemoteViewController], MPMediaPickerController.m:523
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'remoteViewController cannot be nil -- process will crash inserting in hierarchy. We likely got a nil remoteViewController because Music is crashing.'
*** First throw call stack:
(0x1869cac70 0x183499224 0x1844f9f50 0x1a6c6a060 0x18d45518c 0x18d4cd410 0x103354544 0x10336dccc 0x10338f748 0x103364204 0x103364144 0x186957a64 0x1868e5288 0x1868e41d0 0x22bde7498 0x18c5a5ca0 0x18c510254 0x18c71ce90 0x103854340 0x1038542b0 0x103854430 0x1834f1c1c)
libc++abi: terminating due to uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'remoteViewController cannot be nil -- process will crash inserting in hierarchy. We likely got a nil remoteViewController because Music is crashing.'
Hello.
To determine wether "AVB/EAV Mode" of a AV-capable network interfaces is turned on or off I query the IO registry and evaluate the property "AVBControllerState".
I was wondering if this is the "correct" approach and if there is anything known about the values for this property?
Network interfaces without AV capability may also carry this property (e.g.: for my WiFi adapter the value of 1) whereas the value for interfaces with AV capability can be 0 and 3. At least as far as I could observe with my limited amount of test devices at hand.
Is it safe to assume that a value of 3 means this feature is turned on, 0 that it is turned off and ignore values of 1?
Is there another approach to get to know the status of the "AVB/EAV Mode"?
Thanks for any insight.
Best regards,
Ingo
I need to apply headphone-specific scenario only when headphones are the sole active playback device in my iOS audio app.
Problem that there is no absolute way to definitively understand that headphones are the sole active playback device
AVAudioSession.currentRoute.outputs portTypes don't guarantee headphones:
let session = AVAudioSession.sharedInstance()
let outputs = session.currentRoute.outputs
let headphonesOnly = outputs.count == 1 &&
(outputs.first?.portType == .headphones ||
outputs.first?.portType == .bluetoothA2DP ||
outputs.first?.portType == .bluetoothHFP ||
outputs.first?.portType == .bluetoothLE)
The issue in code above that listed bluetooth profiles (A2DP, HFP, LE) can be used by any audio device, not only headphones
Is there any public API on iOS that can:
Distinguish Bluetooth headphones vs Bluetooth speakers when both use A2DP/LE?
Expose the user’s “Device Type” classification (headphones / speaker / car stereo, etc.) that is shown in Settings → Bluetooth → Device Type?
Provide a more reliable way to know “this route is definitely headphones” for A2DP devices, beyond portType and portName string heuristics?
Hi folks - I'm having trouble finding specific documentation about Audio Unit MIDI plugins - as in MIDI -only. Any suggestions welcome as searches aren't returning much. (too niche? user error?)
Topic:
Media Technologies
SubTopic:
Audio
According to the header file the outputVolume properties supported range is 0.0-1.0:
/*! @property outputVolume
@abstract The mixer's output volume.
@discussion
This accesses the mixer's output volume (0.0-1.0, inclusive).
@property (nonatomic) float outputVolume;
However when setting the volume to 2.0 the audio does indeed play louder. Is the header file out of date and if so, what is the supported range for outputVolume?
Thanks
When multiple identical songs are added to a playlist, Playlist.Entry.id uses a suffix-based identifier (e.g. songID_0, songID_1, etc.). Removing one entry causes others to shift, changing their .id values. This leads to diffing errors and collection view crashes in SwiftUI or UIKit when entries are updated.
Steps to Reproduce:
Add the same song to a playlist multiple times.
Observe .id.rawValue of entries (e.g. i.SONGID_0, i.SONGID_1).
Remove one entry.
Fetch playlist again — note the other IDs have shifted.
FB18879062
Hi,
I am looking for a good way to play sounds at a high frequency.
At the moment I am using the AVAudioEngine, and create a couple AVAudioPlayerNode and for each sound I need to play I create a AVAudioPCMBuffer.
When the app needs to play a sound, I get the correct AVAudioPCMBuffer for the sound and use the first available AVAudioPlayerNode and feed it to the buffer.
The timing for a metronome app has to be very precise because if it's of by about 16ms the user can hear that it is not playing had the right interval. For low speeds this is working without any problems, but at high speeds it is getting worse.
Maybe anyone has an idea on how I can improve my method.
Its a Plugin for Flutter.
import AVFoundation
class FastSoundPlayer {
private var audioPlayers: [SoundPlayer?] = []
private var sounds: [String: Sound] = [:]
private var engine = AVAudioEngine()
let session = AVAudioSession.sharedInstance()
init() {
do {
try session.setCategory(AVAudioSession.Category.playback, mode: AVAudioSession.Mode.default, options: [AVAudioSession.CategoryOptions.mixWithOthers])
try session.setActive(true)
createSoundPlayers(count: 20)
try engine.start()
} catch {
print("Error starting audio engine: \(error.localizedDescription)")
}
}
// Selector method to handle applicationDidBecomeActiveNotification
func applicationDidBecomeActive() {
// Reinitialize AVAudioEngine and reattach all nodes
do {
engine.reset()
objc_sync_enter(audioPlayers)
audioPlayers.removeAll()
createSoundPlayers(count: 20)
objc_sync_exit(audioPlayers)
try engine.start()
} catch {
print("Error starting audio engine: \(error.localizedDescription)")
}
}
func createSoundPlayers(count: Int) {
for _ in 0..<count {
let player = SoundPlayer()
engine.attach(player.player)
engine.connect(player.player, to: engine.mainMixerNode, format: nil)
audioPlayers.append(player)
}
}
func load(sound: Data, name: String) {
let sound = Sound(soundData: sound)
sounds[name] = sound
}
func play(name: String) {
if !engine.isRunning {
applicationDidBecomeActive()
}
guard let sound = sounds[name] else {
print("Sound not found")
return
}
if let player = getAvailablePlayer() {
player.play(sound: sound)
}
}
func getAvailablePlayer() -> SoundPlayer? {
for player in audioPlayers {
if !player!.isPlaying {
return player
}
}
return nil
}
}
class SoundPlayer {
let player = AVAudioPlayerNode()
var isPlaying = false
init() {
player.volume = 1.0
}
func play(sound: Sound) {
player.scheduleBuffer(sound.sound!, at: nil, options: .interrupts, completionCallbackType: .dataPlayedBack) { _ in
self.complete()
}
if (player.engine != nil && player.engine!.isRunning) {
player.play()
isPlaying = true
}
}
func complete() {
isPlaying = false
}
}
class Sound {
var sound: AVAudioPCMBuffer?
init(soundData: Data) {
do {
let temporaryURL = FileManager.default.temporaryDirectory.appendingPathComponent("tempSound.wav")
try soundData.write(to: temporaryURL)
// Create AVAudioFile from the temporary file URL
let audioFile = try AVAudioFile(forReading: temporaryURL)
// Define the format for the PCM buffer (44100Hz, stereo)
let format = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: 44100, channels: 2, interleaved: false)
// Create AVAudioPCMBuffer
guard let pcmBuffer = AVAudioPCMBuffer(pcmFormat: format!, frameCapacity: AVAudioFrameCount(audioFile.length)) else {
// Failed to create PCM buffer
self.sound = nil
return
}
// Read audio file into PCM buffer
try audioFile.read(into: pcmBuffer)
// Assign the created AVAudioPCMBuffer to the sound property
self.sound = pcmBuffer
} catch {
print("Error loading sound file: \(error.localizedDescription)")
self.sound = nil
}
}
}
Thanks!