Playing background music with Sprite Kit - swift

I am new to Sprite Kit and currently developing my first Game.
Now I want to add some background music (and maybe later some effects) to it and tried it with this piece of code:
func playBackgroundMusic() {
// 1 - Create player
let url = Bundle.main.url(forResource: "mySong", withExtension: "mp3")!
let player = try! AVAudioPlayer(contentsOf: url)
// 2 - Play sound
player.play()
}
But for some reason it doesn't work. I noticed that when I play music and then run the game, the music stops but I can't hear my game music.

The player variable is local to the playBackgroundPlayer function. When you start playing the music, the function exits. When the function exits, player no longer exists. That would explain why the music stops.
The fix is to add a property for the AVAudioPlayer to the class or struct that contains the playBackgroundPlayer function. Create the AVAudioPlayer instance when you init the class or struct. Call the play function inside playBackgroundPlayer.

Related

How to play video file in AVPlayer outside of app bundle

How do I play a video file which is not included in my app bundle?
I am able to play videos within my app bundle
#IBOutlet weak var playerView: AVPlayerView!
override func viewDidLoad() {
super.viewDidLoad()
let videoUrl = Bundle.main.url(forResource: "captionsSample", withExtension: "mp4")!
let item = AVPlayerItem(url: videoUrl)
let player = AVPlayer(playerItem: item)
playerView.player = player
}
But when I try to play from desktop or some other location, AVPlayer wont play it.
I would like to build a video player which plays a video file as soon as it gets clicked.
I also checked the Apple tutorial, but it only demonstrates how to play videos at the remote location.
As #vadian suggested, the issue was that my application was sandboxed. If you turn off sandboxing you will be able to read/write any file outside of app bundle. This may seam like a convenient solution, but is not recommended. The recommended way would be to leave the sanboxing turned on and add the needed permissions to your entitlements file.

How to detect the end of a song in MusicKit?

I am attempting to use Apple's Music Kit within my application to listen to music. My issue is that the first song that plays will continually repeat. The first song plays correctly by using the following code:
let mediaArray = [songsApple?[songNumber!]]
let playableColledction = MPMediaItemCollection.init(items: mediaArray as! [MPMediaItem])
applicationMusicPlayer.setQueue(with: playableCollection)
applicationMusicPlayer.play()
self.activateAudioSession
The activateAudioSession method is:
do {
try audioSession.setCategory(AVAudioSessionCategoryPlayback)
try audioSession.setActive(true)
}
catch let error {
print(error.localizedDescription)
}
To detect the end of the song, I use the following observer from the Apple Music Documentation:
applicationMusicPlayer.beginGeneratingPlaybackNotications()
NotificationCenter.default.addObserver(self, #selector(didFinishSong), name: Notification.Name.MPMusicPlayerControllerNowPlayingItemDidChange, object: nil)
The didFinishSong method is used to get the songNumber of the next song to be played from the songsApple array. This information is then passed back into the method that plays the song to get the mediaArray. However, right now, didFinishSong does not get called when the song playing finishes and instead the song just repeats from the beginning.
Is there something that I am doing wrong for detecting the end of a song? Is there another way to do it? I also tried to use a timer, but for some reason it would stop counting whenever the application entered the background making the count inaccurate.
Thank you in advance for any help that you are able to provide. If you need additional information please to not hesitate to ask and I will clarify more.

Missing sound on Apple Watch after resume from dock

I am using the following sounds (all 32K AAC as mentioned in Apple document but I use mono instead of stereo: https://developer.apple.com/library/content/documentation/General/Conceptual/WatchKitProgrammingGuide/AudioandVideo.html) for my watchOS 3 games.
let hitSound = SKAction.playSoundFileNamed("hit.m4a", waitForCompletion:false)
let explosionSound = SKAction.playSoundFileNamed("explosion.m4a", waitForCompletion:false)
let music = SKAudioNode(fileNamed: "delta.m4a")
I use hitSound and explosionSound for short sound effect, and play music on the background, they works fine until the game is quit and resume from dock.
The music is resume and the sound effects are no longer heard. Is there any problem with using SKAction.playSoundFileNamed to play sound?

Detect which music from another app is playing in background

I am trying to detect which music from another app is playing in background.
I know there is a way to detect if a music is played in background but I would like to detect which song and the time if I can. How do I do that? In Swift or Objective-c
You can use the MediaPlayer framework to get the current Music playing in the Music app:
import MediaPlayer
let player = MPMusicPlayerController.systemMusicPlayer()
let currentSongTitle = player.nowPlayingItem?.title
let currentPlaybackTime = player.currentPlaybackTime
Note that you need to have the NSAppleMusicUsageDescription (aka Privacy - Media Library Usage Description) set to the String you want to present to the user when asking for permission.

SKAudioNode play sound once

I can't seem to find much information about SKAudioNode. How do i play a sound only once? I do not want to repeat the sound.
What i am trying to accomplish is to play a short laser sound each time a bullet spawns, in spritekit.
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.
if you are trying to do sound effects, you use SKAction.playSoundFileNamed(...) on the sprite that is creating the effect. SKAudioNode is more for having music playing in your game
Example:
//we have ship as an SKSpriteNode
//lets fire laser
ship.runAction(SKAction.playSoundFileNamed("pewpewpew.caf",waitForCompletion:false));