![](/img/trans.png)
[英]How do I ensure my media will continue playing when using AV Foundation while my application is in the background?
[英]How can I allow background music to continue playing while my app still plays its sounds while using Swift
我創建了一個應用程序,我試圖讓用戶在玩我的游戲時繼續聽他們的音樂,但是每當他們點擊“播放”並且游戲中的聲音出現時,它就會停止背景音樂。 我正在使用 Swift 在 iOS 上進行開發。 這是一段啟動游戲聲音的代碼。
func playSpawnedDot() {
var alertSound: NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("spawnDot", ofType: "mp3")!)!
var error:NSError?
audioPlayer = AVAudioPlayer(contentsOfURL: alertSound, error: &error)
audioPlayer.prepareToPlay()
if volumeBool {
audioPlayer.play()
}
}
您需要使用以下值之一設置AVAudioSession
類別: https : //developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVAudioSession_ClassReference/index.html (AVAudioSession 類參考)。
默認值設置為AVAudioSessionCategorySoloAmbient
。 你可以讀到:
[...] 使用此類別意味着您的應用程序的音頻是不可混合的——激活您的會話將中斷任何其他同樣不可混合的音頻會話。 要允許混合,請改用
AVAudioSessionCategoryAmbient
類別。
在播放聲音之前,您必須更改類別。 這樣做:
AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient, error: nil)
AVAudioSession.sharedInstance().setActive(true, error: nil)
每次播放聲音時都不需要調用這些線路。 你可能只想做一次。
斯威夫特 4版本:
try? AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient)
try? AVAudioSession.sharedInstance().setActive(true)
這就是我在 Swift 3.0 中的做法
var songPlayer : AVAudioPlayer?
func SetUpSound() {
if let path = Bundle.main.path(forResource: "TestSound", ofType: "wav") {
let filePath = NSURL(fileURLWithPath:path)
songPlayer = try! AVAudioPlayer.init(contentsOf: filePath as URL)
songPlayer?.numberOfLoops = -1 //logic for infinite loop
songPlayer?.prepareToPlay()
songPlayer?.play()
}
let audioSession = AVAudioSession.sharedInstance()
try!audioSession.setCategory(AVAudioSessionCategoryPlayback, with: AVAudioSessionCategoryOptions.duckOthers) //Causes audio from other sessions to be ducked (reduced in volume) while audio from this session plays
}
您可以在此處查看更多 AVAudioSessionCategoryOptions: https : //developer.apple.com/reference/avfoundation/avaudiosessioncategoryoptions
這是我用於 Swift 2.0 的內容:
let sess = AVAudioSession.sharedInstance()
if sess.otherAudioPlaying {
_ = try? sess.setCategory(AVAudioSessionCategoryAmbient, withOptions: .DuckOthers)
_ = try? sess.setActive(true, withOptions: [])
}
請注意,如果您不想降低背景音樂而是在上面播放,您可以將.DuckOthers
替換為[]
。
lchamp 的解決方案非常適合我,適用於 Objective-C:
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
**
**
我正在播放的聲音的名稱是 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);
}
}
然后你想在哪里播放聲音電話
shatterSound()
因為他們似乎無法從一個版本到另一個版本下定決心。 這是 Swift 5.0
do{
try AVAudioSession.sharedInstance().setCategory(.ambient)
try AVAudioSession.sharedInstance().setActive(true, options: .notifyOthersOnDeactivation)
} catch {
NSLog(error.localizedDescription)
}
如果您想播放提示音:
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)")
}
}
如果你想播放音樂:
導入 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)")
}
}
對於 Swift(Objective-C 也是這樣)
您可以使用此鏈接獲得最佳答案,如果您沒有時間觀看 10 分鍾,最好的操作是您只需copy
以下代碼copy
到您的AppDelegate
中的didFinishLaunchingWithOptions
,然后選擇您的project's target
然后轉到Capabilities
,最后在Background modes
檢查Audio, AirPlay and Picture in Picture
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(AVAudioSessionCategoryPlayback)
}
catch {
}
}
我不認為只是將 AVAudioSession 設置為 AVAudioSessionCategoryOptions.duckOthers 會起作用,但確實如此。 這是我的完整代碼,可以幫助像我這樣的菜鳥。
Swift 4 - 完整示例:
var audioPlayer = AVAudioPlayer()
func playSound(sound: String){
let path = Bundle.main.path(forResource: sound, ofType: nil)!
let url = URL(fileURLWithPath: path)
let audioSession = AVAudioSession.sharedInstance()
try!audioSession.setCategory(AVAudioSessionCategoryPlayback, with: AVAudioSessionCategoryOptions.duckOthers)
do {
audioPlayer = try AVAudioPlayer(contentsOf: url)
audioPlayer.play()
} catch {
print("couldn't load the file")
}
}
我仍然需要弄清楚 setActive ( 我正在看這篇博客文章)但是當我離開應用程序時音頻停止閃避,所以它適用於我的應用程序。
Swift 5 版本基於 lchamp 的回答。
try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.ambient)
try? AVAudioSession.sharedInstance().setActive(true)
這在iOS 14.4 和 Swift 5上非常適合我。 通過使用.duckOthers
選項,它與其他人的答案有點不同(如果您願意,也可以直接與聲音混合.mixWithOthers
),但它在播放音樂時效果很好。 它將降低音樂音量,播放“嗶”聲,然后將音樂音量調高至正常。 如果出現問題,它還會使用 Google Firebase Crashlytics 捕獲錯誤數據,並且即使出現錯誤也會嘗試將音量提高到正常水平。
此代碼也可以在第一次和所有其他聲音播放時完美運行,而不會停止音樂。
func playSound() {
do {
if let path = Bundle.main.path(forResource: "beep", ofType: "mp3") {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: .duckOthers)
try AVAudioSession.sharedInstance().setActive(true)
let filePath = NSURL(fileURLWithPath:path)
songPlayer = try AVAudioPlayer.init(contentsOf: filePath as URL)
songPlayer?.numberOfLoops = 0
songPlayer?.prepareToPlay()
songPlayer?.play()
try AVAudioSession.sharedInstance().setActive(false)
}
} catch (let error) {
try? AVAudioSession.sharedInstance().setActive(false)
Crashlytics.crashlytics().setCustomValue(error.localizedDescription, forKey: "audio_playback_error")
}
}
其他人的答案沒有的一件重要的事情是,您需要在停用時使用 .notifyOthers 標志調用 false :
try AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation)
這樣做的原因是其他在后台播放音樂的應用程序會在您停用您的應用程序時知道何時重新打開它們的音頻。 否則,如果您關閉會話,您的背景音樂將不會重新打開。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.