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 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 not load sound from url
i think you try AVAudioPlayer
var resourcePath = url //your url
var objectData = Data(contentsOf: NSURL(string: resourcePath)!)
var error: Error!
do {
audioPlayer = try AVAudioPlayer(objectData)
}
catch let error {
}
audioPlayer.numberOfLoops = 0
audioPlayer.volume = 1.0
audioPlayer.prepareToPlay()
if audioPlayer == nil {
print("\(error.description)")
}
else {
audioPlayer.play()
}
SKAudioNode else/if off/on Case
Every time you are pressing the sound button you are creating a new instance of SKAudioNode which probably causes the sound issues.
Take theses two lines
let playguitar: SKAudioNode
playguitar = SKAudioNode(fileNamed: "guitar.wav")
out of
func fireTurnsOnOff() {...
Than put
let playguitar: SKAudioNode
above DidMoveToView as a class/global property and
playguitar = SKAudioNode(fileNamed: "guitar.wav")
inside didMoveToView.
SKAudioNode play sound once
Unfortunately, what @KnightOfDragon says is not correct (but I do not have enough reputation to comment).
SKAudioNode
has been introduced in iOS 9 and is meant as a replacement for SKAction.playSoundFileNamed(...)
as it is much more powerful (You can add it as a child to a SpriteKit SKNode
and if the attribute positional
is set to true, 3D audio mixing is added automatically).
In order to play a sound once with SKAudioNode
use the following code:
if #available(iOS 9, *) {
let pling = SKAudioNode(fileNamed: "pling.wav")
// this is important (or else the scene starts to play the sound in
// an infinite loop right after adding the node to the scene).
pling.autoplayLooped = false
someNode.addChild(pling)
someNode.runAction(SKAction.sequence([
SKAction.waitForDuration(0.5),
SKAction.runBlock {
// this will start playing the pling once.
pling.runAction(SKAction.play())
}
])
}
else {
// do it the old way
}
Update
Have a look here, how to use Actions on audio nodes: SKAction->Audio-Stuff. The documentation says:
Use SKAction playSoundFileNamed:waitForCompletion: only for short incidentals.
Use AVAudioPlayer for long running background music.
This does not mean, that a SKAudioNode
should not be used for one-time audio. With playSoundFileNamed
you cannot change the volume or pause/stop playback and so on.
Assign the SKAction returned when running play() on an SKAudioNode?
SKAction.play()
returns an SKAction
, and
mySoundNode.run(SKAction.play())
runs that action on mySoundNode
. The run()
method returns Void
("nothing"), so with
var mySoundAction = mySoundNode.run(SKAction.play())
you run the "play" action on the node and assign ()
to var mySoundAction
. What you perhaps meant is
var mySoundAction = SKAction.play()
// ...
self.run(mySoundAction)
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.
Volume of SKAudioNode
if you ctrl-click on the action on the code in Xcode it pops up with the details of the parameters
class func changeVolume(to v: Float, duration: TimeInterval) ->
SKActionDescription - Creates an action that changes an audio node’s volume to
a new value. When the action executes, the audio node’s volume
animates from its current value to its new value. For more
information, see AVAudio3DMixing.This action - v The new value for the volume. The value should be
between 0.0 (silence) and 1.0 (maximum value for source audio),
inclusive.duration - The duration of the animation, in seconds.
Returns A new action object.
SDKs iOS 9.0+, macOS 10.11+, tvOS 9.0+, watchOS 2.0+
Related Topics
Format String with Trailing Zeros Removed for X Decimal Places in Swift
Using Just with Flatmap Produce Failure Mismatch. Combine
If a Function Returns an Unsafemutablepointer Is It Our Responsibility to Destroy and Dealloc
How to Define an Enum as a Subset of Another Enum's Cases
Adding Nscoding as an Extension
Xcode Autocomplete Does Not Work in Sources Folder of Swift Playgrounds
Using a Mtltexture as the Environment Map of a Scnscene
Swiftui Navigationview Trying to Pop to Missing Destination (Monoceros)
Easiest Way to Find Square Root in Swift
Swift: How to Animate the Rowheight of a Uitableview
Xcode 6 Beta/Swift - Playground Not Updating
iOS 13.1 Uitextview Delegate Method Shouldinteract Called When Scrolling on Attachment
Optional Chaining with Swift Strings
Swift Combine - Wait for All Publishers