Audio glitching on Swift loop - ios

I'm working on an iOS app that has ambient music playing in the background in a -1 (infinite) loop. However, if the user clicks a button on the layout, the audio glitches randomly. Sometimes it doesn't at all.
Here is my code:
if let bundle = Bundle.main.path(forResource: "ambient_audio", ofType: "mp3") {
let backgroundMusic = NSURL(fileURLWithPath: bundle)
do {
audioPlayer = try AVAudioPlayer(contentsOf:backgroundMusic as URL)
guard let audioPlayer = audioPlayer else { return }
audioPlayer.numberOfLoops = -1 // for infinite times
audioPlayer.prepareToPlay()
audioPlayer.play()
} catch {
print(error)
}
}
It is a relatively small issue, sometimes it doesn't occur at all. But when it does, it is annoying.
I have tried many solutions, but none have worked (E.G. background threads).

Related

Keep audio-play while sleeping

I have an iOS app using AVFoundation and playing audio contents.
Once launched I want it to keep playing, even in the background, until I stop it.
But now as soon as the device goes to sleep or I put the app in the background, it stops playing. How can I fix this and get the behavior I wish.
Here is the kind of code I am using in the app:
var soundSession:AVAudioSession!, audioPlayer: AVAudioPlayer?
.....
soundSession = AVAudioSession.sharedInstance()
.....
do {try soundSession.setCategory(AVAudioSession.Category.playback)
try soundSession.setActive(true)
if audioPlayer == nil {
audioPlayer = try AVAudioPlayer(contentsOf: url,
fileTypeHint: fileTypHint)
guard let _ = audioPlayer else {return}
audioPlayer!.delegate = self
}
audioPlayer?.play()
} catch {
print("Error in \(#function)\n" + error.localizedDescription)
}

Swift 4: How to have a sound play over itself when a button is pushed?

So my current situation is that whenever I press a button, the sound will restart from the beginning and cut off the already playing sound. What I want is the sound to play over itself when I push the button, so if I push it a second time right after the first time, the second sound would play over the first one and not cut it off. Please let me know if you need clarification on what I need. Here is my code so far:
#IBAction func bull(_ sender: Any) {
let url = Bundle.main.url(forResource: "Bull", withExtension: "mp3")!
do
{
player = try AVAudioPlayer(contentsOf: url)
guard let player = player else { return }
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
player.prepareToPlay()
player.play()
}
catch let error
{
print(error.localizedDescription)
}
}
Thanks.
One player can play one sound at a time only. You probably have to do following
Create an array of players
var arrPlayer: [AVAudioPlayer] = []
And then inside your method do the following
let url = Bundle.main.url(forResource: "Bull", withExtension: "mp3")!
do
{
player = try AVAudioPlayer(contentsOf: url)
arrPlayer.append(player)
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient)
try AVAudioSession.sharedInstance().setActive(true)
arrPlayer.last?.prepareToPlay()
arrPlayer.last?.play()
}
catch let error
{
print(error.localizedDescription)
}

Music playing over the song when i return to the original VC

I am using xcode 9 and swift 4 for my app. In my app i have music playing in the viewDidLoad. When i exit the view controller to go to another View, it continues to play like it should. How ever, when i return to that view controller the song starts to play again. This song is overlapping the song that first loaded. Do you guys have any ideas on how to stop this from happening?
do
{
let audioPath = Bundle.main.path(forResource: "APP4", ofType: "mp3")
try player = AVAudioPlayer(contentsOf: NSURL(fileURLWithPath: audioPath!) as URL)
}
catch
{
//catch error
}
let session = AVAudioSession.sharedInstance()
do
{
try session.setCategory(AVAudioSessionCategoryPlayback)
}
catch
{
}
player.numberOfLoops = -1
player.play()
It starts playing again, because your viewDidLoad is called again, which asks it to play it again. A simplest fix would be to keep a static bool variable to keep track if you have already made this call.
static var isMusicPlaying: Bool = false
In your viewDidLoad, you can put code before the code that calls the play.
guard !isMusicPlaying else {
return
}
isMusicPlaying = true

iOS: audio files used in app sound harsher than when played outside the app

The audio files for our iOS app sound much worse when played through the app than when played outside the app. The sounds seem harsher and more "ecohy".
Here's our code for playing audio. Are we somehow altering the playback or natural sound of the audio?
Two of the audio files we're using can be found here:
private func createAudioPlayer(filename: String) -> AVAudioPlayer {
// Define file URL
let path = Bundle.main.path(forResource: filename, ofType: nil)
let url = URL(fileURLWithPath: path!)
// Create player
let audioPlayer: AVAudioPlayer!
do {
audioPlayer = try AVAudioPlayer(contentsOf: url)
} catch {
audioPlayer = nil
printError("Error creating audio player for \(url): \(error)")
logEvent("Audio Error", userData: nil)
}
// Print status
print("Created audio player for \(filename)")
// Return player
return audioPlayer
}
func play(file: AudioFileEnum) {
if let player = audioPlayers[file] {
if player.isPlaying {
player.pause()
}
player.currentTime = 0
player.play()
} else {
printError("Error finding audio player for \(file)")
}
}
Have you tried setting the volume on the audioPlayer object to something smaller, like 0.05f, and adjusting from there?

AVAudioPlayer produces lag playing sound effect

I'm using the SKTAudio library given by Ray Wenderlich on his Github. Here's the code I've modified for playing a sound effect that I call everytime I play one:
public func playSoundEffect(_ filename: String) {
let url = Bundle.main.url(forResource: filename, withExtension: nil)
if (url == nil) {
print("Could not find file: \(filename)")
return
}
if !UserDefaults.standard.bool(forKey: "soundOff"){
var error: NSError? = nil
do {
soundEffectPlayer = try AVAudioPlayer(contentsOf: url!)
} catch let error1 as NSError {
error = error1
soundEffectPlayer = nil
}
if let player = soundEffectPlayer {
DispatchQueue.global(qos: .background).async {
player.numberOfLoops = 0
player.prepareToPlay()
player.play()
}
} else {
print("Could not create audio player: \(error!)")
}
}
}
I'm using this because this way I can mute the sound effects easily, since this is using a singleton class method. The thing is, this produces minor lag everytime I play a sound effect. If I mute the game, no lag. I tried making the sound play in a background thread, but the result is the same.
Is there any easy change to this code to make it have NO LAG?
EDIT: This is not a duplicate because none of the other answers on other questions solved my problem.

Resources