Cannot play audio file without app crashing on device running ios 13 - ios

I have an app being used by people to receive orders with it needing to make a continuous sound until staff attend to it. It was working for two months then just started crashing a lot. For whatever reason, it runs fine on an iPad but not on iPhones running a recent operating system.
When this bit of code gets called it crashes:
guard let path = Bundle.main.path(forResource: "alert.mp3", ofType: nil) else { return }
let url = URL(fileURLWithPath: path)
do {
self.alertSoundEffect = try AVAudioPlayer(contentsOf: url)
} catch let err {
print("err: \(err)")
}
DispatchQueue.main.async {
self.alertSoundEffect.numberOfLoops = -1
self.alertSoundEffect.prepareToPlay()
self.alertSoundEffect.play()
}
The fix online to declare the alertSoundEffect variable like this:
private var alertSoundEffect : AVAudioPlayer!
has not worked at all.
I tried moving everything but the line:
self.alertSoundEffect.play()
to viewDidLoad as I thought maybe that code couldn't get called more than once, but it didn't help.
Specifically, the compiler highlights this line when it crashes:
self.alertSoundEffect = try AVAudioPlayer(contentsOf: url)
I tried using try AVAudioPlayer where it takes a Data object as a parameter or with including the type of audio file to be played, but that did not change anything.
When I try the AVAudioPlayer's delegate and declare it like this:
self.alertSoundEffect.delegate = self
right before the first lines of code I shared above Xcode highlights this line instead when it reliably crashes.
What else should I try?

I suppose your path is wrong.
Try this:
guard let path = Bundle.main.path(forResource: "alert", ofType: "mp3") else { return }
Also, if your audio file is short, like less than 30s, then try not to call self.alertSoundEffect.prepareToPlay(). Just call self.alertSoundEffect.play() right away.
Since iOS 13, this was causing a bug in my app, since I have notification sounds which are 3-10 seconds long.

If you initialise your AVAudioPlayer like var wrongMusicPlayer: AVAudioPlayer = AVAudioPlayer() OR wrongMusicPlayer = AVAudioPlayer() in any method then please remove it and just Declare like var wrongMusicPlayer: AVAudioPlayer!.
iOS 13.1 Crash in AVAudio Player

Related

AVAudioPlayer will not play audio for one mp3 but will for others?

All of my other audio files play perfectly through the audio player. Most of the files are less than 5 seconds long, and the longest file that still plays is 23 seconds long. For some reason my 1:15 long file "sortSong" is completely silent when it is called.
Here is the code for my audio player:
import Foundation
import AVFoundation
class AudioPlayer {
static let sharedInstance = AudioPlayer()
enum Sound: String {
case sortSongPlay = "sortSong"
case centerButtonRelease = "centerButtonRelease"
case buttonTap = "tapSound"
static var all: [Sound] {
return [.centerButtonRelease, .buttonTap, sortSongPlay]
}
var url: URL {
return URL.init(fileURLWithPath: Bundle.main.path(forResource: self.rawValue, ofType: "mp3")!)
}
}
private var soundMap = [String: SystemSoundID]()
init() {
for sound in Sound.all {
let soundUrl = sound.url
var soundId: SystemSoundID = 0
AudioServicesCreateSystemSoundID(soundUrl as CFURL, &soundId);
soundMap[sound.rawValue] = soundId
}
}
func play(sound: Sound) {
AudioServicesPlaySystemSound(soundMap[sound.rawValue]!)
}
}
The sound is played when this function is called in my view controller.
func successfulSort() {
AudioPlayer.sharedInstance.play(sound: .sortSongPlay)
rotateSortImageOne()
rotateSortImageTwo()
}
This is the action that calls the successfulSort func
if inputText == "hello" && seedArray == [1, 4, 1] {
successfulSort()
}
If I simply change the case sortSongPlay to = "shortSortSong" (the 23 second version) it plays just fine.
All of my sound files have their target memberships checked for this project file, and all of the files have the correct path. The audio will play in the interface builder if I press the play button. There are no compiler errors or warnings, the app never crashes, the audio for sortSong simply isn't playing when it is called in the app.
This is a link containing examples I have tried on my project. The first two sounds play silently in the app while the shorter sounds all play perfectly. https://soundcloud.com/spiffystache
What is causing this to be silent?
You should put a correct title on your question.
Your code does not use AVAudioPlayer, but uses System Sound Services.
The documentation clearly states its limitation:
You can use System Sound Services to play short (30 seconds or
shorter) sounds.
I have never checked if its limitation is exactly 30 seconds, but it matches the description in your question.
Consider using AVAudioPlayer (as in the title) to play longer sound.

AudioToolBox in Swift - Sound works in Simulator but not on my IPad

I'm creating a music app where different chimes will be played at different points in a rhythm cycle. So far, my code works fine in the Simulator but I'm not getting any sound on my device. I get sounds from other apps. Is there something wrong with my code? Thanks for you help!
import UIKit
import AudioToolbox
func playChime1() {
var chime1URL: NSURL?
var chime1ID:SystemSoundID = 0
let filePath = NSBundle.mainBundle().pathForResource("Chime", ofType: "mp3")
chime1URL = NSURL(fileURLWithPath: filePath!)
AudioServicesCreateSystemSoundID(chime1URL!, &chime1ID)
AudioServicesPlaySystemSound(chime1ID)
}
func playChime2() {
var chime2URL: NSURL?
var chime2ID:SystemSoundID = 0
let filePath = NSBundle.mainBundle().pathForResource("Chime2", ofType: "mp3")
chime2URL = NSURL(fileURLWithPath: filePath!)
AudioServicesCreateSystemSoundID(chime2URL!, &chime2ID)
AudioServicesPlaySystemSound(chime2ID)
}
func playChime3() {
var chime3URL: NSURL?
var chime3ID:SystemSoundID = 0
let filePath = NSBundle.mainBundle().pathForResource("Chime3", ofType: "mp3")
chime3URL = NSURL(fileURLWithPath: filePath!)
AudioServicesCreateSystemSoundID(chime3URL!, &chime3ID)
AudioServicesPlaySystemSound(chime3ID)
}
I had the same issue and realised my iPhone was on silent mode, taking it off silent played the sounds.
Unfortunately AudioToolbox sounds respond to the 'Ringer' volume of the device, and not the 'Volume' setting that audio through AVFoundation uses.
It makes sense, as AudioToolbox is supposed to be used for system sounds.
From related question: AudioServicesPlaySystemSound not working on iPad device
You can't play MP3 on iDevice, need to use a different framework.
My problem was the number of buffers allocated for AudioQueue, I allocated 3 and it worked on MacOS, however for iOS device you need at least 4

AVAudioPlayer sound not playing

In iOS 8/Xcode 6 I had a function that included a sound effect. It no longer works in iOS 9 after changing the code multiple times. This is what I've tried:
Original:
let bangSoundEffect = SKAction.playSoundFileNamed("Bang.mp3", waitForCompletion: false)
runAction(bangSoundEffect)
Other attempt:
self.runAction(SKAction.playSoundFileNamed("Bang.mp3", waitForCompletion: false))
Also:
func playRocketExplosionSound(filename: String) {
let url = NSBundle.mainBundle().URLForResource(
filename, withExtension: nil)
if (url == nil) {
print("Could not find file: \(filename)")
return }
var error: NSError? = nil
do {
backgroundMusicPlayer =
try AVAudioPlayer(contentsOfURL: url!)
} catch let error1 as NSError {
error = error1
backgroundMusicPlayer = nil
}
if backgroundMusicPlayer == nil {
print("Could not create audio player: \(error!)")
return}
backgroundMusicPlayer.numberOfLoops = 1
backgroundMusicPlayer.prepareToPlay()
backgroundMusicPlayer.play() }
playRocketExplosionSound("Bang.mp3")
I'm pulling my hair out. I'm using the same code in a different scene for another sound effect and it works fine!! What's going wrong?
I've noticed that the sound effect begins to play sometimes in the simulator, however it doesn't complete and throws this error:
2015-09-24 19:12:14.554 APPNAME[4982:270835] 19:12:14.553 ERROR: 177: timed out after 0.012s (735 736); mMajorChangePending=0
It doesn't work at all on actual devices.
What is the problem? :'(
Possible problem with MP3 file
The problem is most likely connected with the MP3 file you're using. The code works for other sounds, this suggests that the MP3 file might be corrupted and AVAudioPlayer fails with decoding it. You can try re-encode this file and see if the problem persists. Or, even better, converting it to WAV.
Using WAVs
General rule of the thumb when creating short sound effects for games, is to use WAV unless you really feel you need the trim the fat.
Top-notch games are going for top-of-the-line production quality, so they record and produce assets uncompressed 24bit/48kHz. Titles with slightly lesser ambitions might record and produce in 16/44.1, which is the official standard for CD quality audio.
This has at least two benefits. One is that the sound has a better quality. Second one, the CPU does not have to decode the file to play it.
Corrupt data file | AVAudioPlayer out of scope
1. Corrupt data file
This will ensure you have found the file:
var backgroundMusicPlayer: AVAudioPlayer? = nil
if let url = Bundle.main.url(
forResource: "Bang", withExtension: "mp3") {
do {
try backgroundMusicPlayer = AVAudioPlayer(contentsOf: url)
backgroundMusicPlayer!.play()
} catch {}
}
return nil
2. AVAudioPlayer out of scope
The variable retaining backgroundMusicPlayer must not go out of scope before play() has completed and returns. This is generally achieved by using a class variable:
var backgroundMusicPlayer: AVAudioPlayer? = nil
Don't do this: the following sound will play for, at best, outOfScopeDelay due to the local scope of var audioPlayer.
let outOfScopeDelay = 0.5
do {
var audioPlayer:AVAudioPlayer! // Incorrectly scoped variable
try audioPlayer = AVAudioPlayer(contentsOf: audioRecorder.url)
audioPlayer.play()
Thread.sleep(forTimeInterval: outOfScopeDelay)
} catch {}
► Find this solution on GitHub and additional details on Swift Recipes.
try this:
dispatch_async(dispatch_get_main_queue(), {
(self.playRocketExplosionSound("Bang.mp3")
})
it's no longer safe to play audio in child thread under iOS 9.

XCode 7 Swift - Call can throw, it it is not markedwith 'try' and the error is not handled

I'm trying to play music on my iOS application when I click a button and I already know how to do it but this time when I insert the line; audioPlayer = AVAudioPlayer(contentsOfURL: audioPlayerURL, error: nil)it will give me an option to change errorto fileTypeHintwhich I do but then I get the following error; `Call can throw, it it is not markedwith 'try' and the error is not handled'.
I don't really understand because in Xcode 6 I used the word error in that line of code and I had no issues with that and playing music was working. There must be a different or similar way of writing that line since I've upgraded to Xcode 7 Beta 3 but I've searched everywhere to see what's changed.
Would anybody know anything about it?
Error handling has changed in Swift 2.0. Use the following try-catch code to resolve the error:
do {
audioPlayer = try AVAudioPlayer(contentsOfURL: audioFileUrl,
fileTypeHint: AVFileTypeMPEGLayer3)
} catch let error as NSError {
print("AV Sound Error: \(error.localizedDescription)")
}
I had the same issue, after piecing together some information this is what I came up with and it works in Swift 2.0.
override func viewWillLayoutSubviews() {
let bgMusicURL:NSURL = NSBundle.mainBundle().URLForResource("bgmusic", withExtension: "mp3")!
backgroundMusicPlayer = try! AVAudioPlayer(contentsOfURL: bgMusicURL)
backgroundMusicPlayer.numberOfLoops = -1
backgroundMusicPlayer.prepareToPlay()
backgroundMusicPlayer.play()
}
Make sure to Import AVFoundation
and also add this in your controller
var backgroundMusicPlayer:AVAudioPlayer = AVAudioPlayer()

Sound not playing on device but works on simulator

Yes I have looked around.
var congratzSound = NSBundle.mainBundle().URLForResource("Sweg.aiff", withExtension: "aiff")
var congratzPlayer:AVAudioPlayer? = AVAudioPlayer()
congratzPlayer = AVAudioPlayer(contentsOfURL: congratzSound, error: nil)
if let congratzPlayer = audioPlayer {
congratzPlayer.play()
}
This code complies fine, the file is in the Supporting Files section AND being coppied to the device.
What am I doing wrong? Is the file extension not playable? Is the congratzSound set up wrong?
Thanks in advance.
Using the following should solve your problem:
var congratzSound = NSBundle.mainBundle().URLForResource("Sweg", withExtension: "aiff")
If that doesn't work, try:
var congratzSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("Sweg", ofType: "aiff")!)
Also, please check whether the file name is as-it-is (Sweg.aiff) in your code project and it is present in your app folder.
It is likely that your device is looking for Sweg.aiff.aiff while trying to play the sound, which obviously doesn't exist

Resources