I created an app and I am attempting to allow the user to continue to listen to their music while playing my game, but whenever they hit \"play\" and the ingame sounds occur
lchamp's solution worked perfectly for me, adapted for Objective-C:
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
Swift 5 Version based on lchamp`s answer.
try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.ambient)
try? AVAudioSession.sharedInstance().setActive(true)
If you want to play an alert sound:
public func playSound(withFileName fileName: String) {
if let soundUrl = Bundle.main.url(forResource: fileName, withExtension: "wav") {
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient, with:[.duckOthers])
try AVAudioSession.sharedInstance().setActive(true)
var soundId: SystemSoundID = 0
AudioServicesCreateSystemSoundID(soundUrl as CFURL, &soundId)
AudioServicesAddSystemSoundCompletion(soundId, nil, nil, { (soundId, clientData) -> Void in
AudioServicesDisposeSystemSoundID(soundId)
do {
// This is to unduck others, make other playing sounds go back up in volume
try AVAudioSession.sharedInstance().setActive(false)
} catch {
DDLogWarn("Failed to set AVAudioSession to inactive. error=\(error)")
}
}, nil)
AudioServicesPlaySystemSound(soundId)
} catch {
DDLogWarn("Failed to create audio player. soundUrl=\(soundUrl) error=\(error)")
}
} else {
DDLogWarn("Sound file not found in app bundle. fileName=\(fileName)")
}
}
And if you want to play music:
import AVFoundation
var audioPlayer:AVAudioPlayer?
public func playSound(withFileName fileName: String) {
if let soundUrl = Bundle.main.url(forResource: fileName, withExtension: "wav") {
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient, with:[.duckOthers])
try AVAudioSession.sharedInstance().setActive(true)
let player = try AVAudioPlayer(contentsOf: soundUrl)
player.delegate = self
player.prepareToPlay()
DDLogInfo("Playing sound. soundUrl=\(soundUrl)")
player.play()
// ensure the player does not get deleted while playing the sound
self.audioPlayer = player
} catch {
DDLogWarn("Failed to create audio player. soundUrl=\(soundUrl) error=\(error)")
}
} else {
DDLogWarn("Sound file not found in app bundle. fileName=\(fileName)")
}
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
self.audioPlayer?.stop()
do {
// This is to unduck others, make other playing sounds go back up in volume
try AVAudioSession.sharedInstance().setActive(false)
} catch {
DDLogWarn("Failed to set AVAudioSession inactive. error=\(error)")
}
}
**
**
The name of the sound I am playing is shatter.wav
func shatterSound() {
if let soundURL = Bundle.main.url(forResource: "shatter", withExtension: "wav") {
var mySound: SystemSoundID = 0
AudioServicesCreateSystemSoundID(soundURL as CFURL, &mySound)
AudioServicesPlaySystemSound(mySound);
}
}
Then where ever you want to play the sound call
shatterSound()
You need to set the AVAudioSession
category, with one of the following value: https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVAudioSession_ClassReference/index.html (AVAudioSession Class Reference).
The default value is set to AVAudioSessionCategorySoloAmbient
. As you can read :
[...] using this category implies that your app’s audio is nonmixable—activating your session will interrupt any other audio sessions which are also nonmixable. To allow mixing, use the
AVAudioSessionCategoryAmbient
category instead.
You have to change the category, before you play your sound. To do so :
AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient, error: nil)
AVAudioSession.sharedInstance().setActive(true, error: nil)
You don't need to call those line each time you play the sound. You might want to do it only once.