AVAudioEngine crashes when plug headphones in or out
You need to register to the AVAudioEngineConfigurationChangeNotification
notification and do the necessary steps to update the output node.
SKAudioNode() crashes when plugging in/out headphones
I was not able fix it, but by using AVAudioPlayer()
I found a good workaround. Thank you all for supporting me!
import SpriteKit
import AVFoundation
class GameScene: SKScene {
var audioPlayer = AVAudioPlayer()
override func didMoveToView(view: SKView) {
initAudioPlayer("gameloop.mp3")
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
_ = touches.first as UITouch!
for _ in touches {
toggleBackgroundMusic()
}
}
func initAudioPlayer(filename: String) {
let url = NSBundle.mainBundle().URLForResource(filename, withExtension: nil)
guard let newURL = url else {
print("Could not find file: \(filename)")
return
}
do {
audioPlayer = try AVAudioPlayer(contentsOfURL: newURL)
audioPlayer.numberOfLoops = -1
audioPlayer.prepareToPlay()
audioPlayer.play()
} catch let error as NSError {
print(error.description)
}
}
func toggleBackgroundMusic() {
if audioPlayer.playing {
audioPlayer.pause()
} else {
audioPlayer.play()
}
}
}
AVAudioEngine uses wrong format when bluetooth headset plugged in
After my failed bounty I wrote to Apple DTS, and got a wonderful response (including the code sample below that I translated from Objective-C).
The function below will connect to the default audio device in output-only mode, instead of the inout/output mode that is the default behavior. Remember to call it before engine start!
func setOutputDeviceFor(_ engine: AVAudioEngine) -> Bool {
var addr = AudioObjectPropertyAddress(
mSelector: kAudioHardwarePropertyDefaultOutputDevice,
mScope: kAudioObjectPropertyScopeGlobal,
mElement: kAudioObjectPropertyElementMaster)
var deviceID: AudioObjectID = 0
var size = UInt32(MemoryLayout.size(ofValue: deviceID))
let err = AudioObjectGetPropertyData(
AudioObjectID(kAudioObjectSystemObject),
&addr,
0,
nil,
&size,
&deviceID)
if (noErr == err && kAudioDeviceUnknown != deviceID) {
do {
try engine.outputNode.auAudioUnit.setDeviceID(deviceID)
} catch {
print(error)
return false
}
return true
} else {
print("ERROR: couldn't get default output device, ID = \(deviceID), err = \(err)")
return false
}
}
AVAudioEngine not posting notification in SpriteKit
The original Cocoa name of the notification is AVAudioEngineConfigurationChangeNotification
, but the Swift constant is called AVAudioEngineConfigurationChange
. Therefore you can handle the notification by using either:
let notificationName = Notification.Name("AVAudioEngineConfigurationChangeNotification")
or
let notificationName = Notification.Name.AVAudioEngineConfigurationChange
Your selector should then be called when plugging-in/unplugging headphones.
This appears to only be a partial solution for SpriteKit audio flakiness. I tried the following inside the notification handler:
try? self.audioEngine.start()
I was able to stop the crash, but my SKAudioNode
wouldn't make any sound after the plug/unplug event, until the process was restarted.
Related Topics
How to Simulate Mouse Click from MAC App to Other Application
Process Array in Parallel Using Gcd
Best Practice for Swift Methods That Can Return or Error
Curl Through Nstask Not Terminating If a Pipe Is Present
How to Capture Depth Data from Camera in iOS 11 and Swift 4
Private Var Is Accessible from Outside the Class
How to Pause and Resume Nstimer.Scheduledtimerwithtimeinterval in Swift
How Constant Is the Firebase Anonymous Id
Add Animations to Foreach Loop Elements (Swiftui)
How to Tell If a Node Is on the Screen Spritekit Swift
Swift Update Label (With HTML Content) Takes 1Min
How Do People Deal with Iterating a Swift Struct Value-Type Property
Checking If an Array of Custom Objects Contain a Specific Custom Object
Swiftui: Prevent Image() from Expanding View Rect Outside of Screen Bounds
Swiftier Swift for 'Add to Array, or Create If Not There...'
How to Copy a Struct and Modify One of Its Properties at the Same Time