Can't play local mp3 above ios13 swift - swift

I have an app that play local mp3 files within the app that doesnt work in iOS 13 but lower os it works....
appending this in the array before:
Declare this in the class:
var MediaPlayer = AVAudioPlayer()
Sending in to the function in viewdidload:
TrackListData.append(Track(TrackName: "Introduction",TrackDescription: "About the good reasons for taking mindful breaks", TrackURL: URL(fileURLWithPath: Bundle.main.path(forResource: "Introduction", ofType: "mp3")!)))
setSong(trackURL: TrackListArray[0].TrackList[0].TrackURL)
func setSong(trackURL : URL){
do{
MediaPlayer.prepareToPlay()
MediaPlayer = try AVAudioPlayer(contentsOf: trackURL)
ProgressbarSong.maximumValue = Float(MediaPlayer.duration)
}
catch {
print(error)
}
}
Get this error in the function setSong at line: MediaPlayer = try AVAudioPlayer(contentsOf: trackURL)
Error:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x58)

Looks like a duplicate of 58166133.
AVAudioPlayer doesn't have an init so you should update your first line, like this
var MediaPlayer: AVAudioPlayer!

Related

Swift 5.1 Error: [plugin] AddInstanceForFactory: No factory registered for id <CFUUID

App crashes with the following error message
2019-10-12 20:01:34.332334-0700 Awesome App[26368:3535170] [plugin] AddInstanceForFactory: No factory registered for id <CFUUID 0x600002903280> F8BB1C28-BAE8-11D6-9C31-00039315CD46
The breakpoint at crash seems to be related to AVAudioPlayer
let path = Bundle.main.path(forResource: "menu_background.mp3", ofType:nil)!
audioPlayer = try AwesomeAudioPlayer(contentsOf: URL(fileURLWithPath: path)) ---> breakpoint
I believe you all might have added the AVFoundation to the frameworks list in Project General Info tab.
Erroneous Code was as follows:
import SwiftUI
import AVFoundation
struct PlayerDetailView: View {
#State private var downloadedFilePath: URL = nil
var audioPlayer: AVAudioPlayer
var body: some View {
And after I moved the var audioPlayer: AVAudioPlayer declaration to just after the line of import AVFoundation line it seemed to be working.
So following code worked for me in a SwiftUI project:
import SwiftUI
import AVFoundation
var audioPlayer: AVAudioPlayer!
struct PlayerDetailView: View {
#State private var downloadedFilePath: URL = nil
var body: some View {
VStack {
Button("Play the Downloaded Track") {
if let downloadedPath = self.downloadedFilePath?.path, FileManager().fileExists(atPath: downloadedPath) {
do {
audioPlayer = try AVAudioPlayer(contentsOf: self.downloadedFilePath!)
guard let player = audioPlayer else { return }
player.prepareToPlay()
player.play()
} catch let error {
print(error.localizedDescription)
}
} else {
print("The file doesn not exist at path || may not have been downloaded yet")
}
}
}
}
}
I was initially following this tutorial of CodeWithChris and its discussion also led to above change. Also checkout following tutorial too if you need further examples.
Hope this will be helpful to someone of you out there!
Cheers!
I believe the error message is a warning for simulators hence it is not important.
I think your issue is a bug in your code. Should be something like this:
let path = Bundle.main.path(forResource: "menu_background", ofType:"mp3")
audioPlayer = try AwesomeAudioPlayer(contentsOf: URL(fileURLWithPath: path!)) ---> breakpoint
Where the forResource is the name of the file and ofType is the extension.
You can also use Bundle.main.url which will look like this:
let path = Bundle.main.url(forResource: "menu_background", withExtension:"mp3")
audioPlayer = try AwesomeAudioPlayer(contentsOf: URL(fileURLWithPath: path!)) ---> breakpoint
I think it has to do with the AVAudioPlayer going out of scope before the simulator device is able to queue up the sound and play it...or something along those lines. I'm brand new to Swift and I have zero experience with iOS APIs.
Here's what I discovered after experimenting with the placement of:
var player: AVAudioPlayer!
The sound will either PLAY or NOT PLAY depending on the placement of the line above.
Regardless, the following error will always occur on my Simulator devices:
AddInstanceForFactory: No factory registered for id
(I'm on a Late 2013 MacBook Pro + MacOS Catalina + Xcode 11.7 and I tested this on an iPhone SE 2 simulator running iOS 13.7)
Although the error keeps occurring, I'm happy that I at least got the sound to play on the Simulator...
Error occurs and sound DOES NOT play...
import UIKit
import AVFoundation
class ViewController: UIViewController {
func playTheSound() {
// initializing the "player" variable within the "playTheSound()" function will cause the "AddInstanceForFactory: No factory registered for id" error and the sound WILL NOT play on the simulator
var player: AVAudioPlayer!
let url = Bundle.main.url(forResource: "funny_sound", withExtension: "mp3")
player = try! AVAudioPlayer(contentsOf: url!)
player.play()
}
}
Error occurs and sound DOES play
import UIKit
import AVFoundation
class ViewController: UIViewController {
// initializing the "player" variable at the class level will still cause the "AddInstanceForFactory: No factory registered for id" error to happen, but the sound will still play on the simulator
var player: AVAudioPlayer!
func playTheSound() {
let url = Bundle.main.url(forResource: "funny_sound", withExtension: "mp3")
player = try! AVAudioPlayer(contentsOf: url!)
player.play()
}
}
In my case totally different...
The issue is solved after doing...
var player = AVAudioPlayer()
It didn't work in...
var player:AVAudioPlayer!
(Xcode 12.2)
I think I have solved the issue (hard to prove a negative, since the error was sporadic). I have my AVAudioPlayer in a separate class:
import SwiftUI
import AVFoundation
var audioPlayer: AVAudioPlayer?
class AudioManager {
var userSettings = UserSettings()
func playSoundEffect(_ assetName:String) {
if !userSettings.soundDisabled {
guard let audioData = NSDataAsset(name: assetName)?.data else {
fatalError("Unable to find asset \(assetName)")
}
do {
audioPlayer = try AVAudioPlayer(data: audioData)
audioPlayer?.prepareToPlay()
audioPlayer?.play()
} catch {
print(error.localizedDescription)
}
}
// audioPlayer?.stop()
}
func stopPlay() {
audioPlayer?.setVolume(0.0, fadeDuration: 0.25)
}
}
Then, in the SwiftUI views where I need to play audio, be certain to import AVFoundation.
import SwiftUI
import AVFoundation
struct MyView: View {
...
let audioManager = AudioManager()
...
}
I have found the solution in another stackoverflow thread about AVAudioPlayer, here it is :
If you initialize your AVAudioPlayer like
var wrongMusicPlayer: AVAudioPlayer = AVAudioPlayer() OR wrongMusicPlayer = AVAudioPlayer() in any method then please remove it and just Declare like var wrongMusicPlayer: AVAudioPlayer!.
You could use do/catch to avoid the crash and examine the exception, or ignore the issue all together with try?. For me, this was only showing up in the simulator when calling:
try? AVAudioSession.sharedInstance().setCategory(.playback)
I think it's safe to ignore it in my case.
Similar problem - using Preferences > Sound > Output different than Logictech USB Headset led to app that executed perfect & played sound w/o problems. Was never a problem outside of the Simulator - code on a device worked fine.
TL;DR
This is an especially gnarly & obtuse problem. I also encountered an issue with an unexpected:
No factory registered for id
After a short wait, it was also followed by several other console-reported errors, including:
HALC_ProxyIOContext::IOWorkLoop: the server failed to start, Error:
AQMEIO.cpp:182:AwaitIOCycle: timed out after 15.000s
CA_UISoundClient.cpp:244:StartPlaying_block_invoke: CA_UISoundClientBase::StartPlaying: AddRunningClient failed
error when trying to play sound. Xcode 12.2, Mac OSX Catalina 10.15.7, simulator running iOS 14.2.
Code had previously worked on prior versions of the simulator.
Always had proper import of AVFoundation & declaration of AVAudioPlayer class property as:
var audioPlayer: AVAudioPlayer!
In my case it seems to be related to audio drivers in Mac OSX. This problem ONLY happened when I had Mac System Preferences > Sound > Output set to my Logitech USB Headset. The code otherwise worked when: played through my LG Monitor, played through my AirPods Pro, and when executing outside the simulator and on a device > my iPhone 11 Pro.
Spent over an hour trying to diagnose the issue before restarting & noticing audio working when headset wasn't used for output. Switching the Preferences > Sound > Output settings to something other than the Logitech USB headset immediately fixed the problem in all other playback instances.
Not even sure where to file this issue as an Apple bug, but hoping it helps someone. Am assuming it's an OS-specific issue & not one that'll result in a problem w/the app or code.
I found a solution in Here2Huynh's answer.
let path = Bundle.main.path(forResource: "menu_background.mp3", ofType:nil)!
here change
ofType:nil
to
ofType: "mp3"
and then again.There is no error message when using the emulator.
By the way, I am using the swiftui project
Simulator -> I/O -> Keyboard -> uncheck all

Audio not playing in SwiftUI

I'm having an issue getting an audio file to play when the function is called.
I am using an AVAudioPlayer to try and play the file following the instructions form here:
https://www.hackingwithswift.com/example-code/media/how-to-play-sounds-using-avaudioplayer
After the button is pressed in the view, it calls a func to play the sound, but from what I can tell, nothing is played. There are no errors thrown, and the file is found. The app also uses a speech synthesizer when a button is pushed, and that plays fine.
I looked around stack overflow and followed the instructions from here:
Where to place code for audio playback in a SwiftUI app
But still the audio is not played when the button is pushed.
Here is the func:
func playSound() {
var sound = AVAudioPlayer()
if let path = Bundle.main.path(forResource: "TryAgain", ofType: "wav") {
do {
sound = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
print("Playing sound")
sound.play()
} catch {
print( "Could not find file")
}
}
Here is the class:
class Player: BindableObject {
let willChange = PassthroughSubject<Player, Never>()
var isPlaying: Bool = false {
willSet {
willChange.send(self)
}
}
func playSound() {
var sound = AVAudioPlayer()
if let path = Bundle.main.path(forResource: "TryAgainWav", ofType: "wav") {
do {
sound = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
print("Playing sound")
sound.play()
} catch {
print( "Could not find file")
}
}
}
}
Update: Not sure if this helps, but I built this in with IB instead of SwiftUI and noticed the same message is printed in the console when I click the button to play the audio file:
2019-07-22 11:29:41.075568-0700 PlaySoundPrac[13952:46549155] [plugin] AddInstanceForFactory: No factory registered for id F8BB1C28-BAE8-11D6-9C31-00039315CD46
Any help would be greatly appreciated
I'm pretty new myself, but I'll do my best. What happens if you move the declaration of AVAudioPlayer outside the function? For example:
import Combine
class Player: ObservableObject {
var sound: AVAudioPlayer!
let willChange = PassthroughSubject<Player, Never>()
var isPlaying: Bool = false {
willSet {
willChange.send(self)
}
}
func playSound() {
if let path = Bundle.main.path(forResource: "TryAgainWav", ofType: "wav") {
do {
sound = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
print("Playing sound")
sound.play()
} catch {
print( "Could not find file")
}
}
}
}
Try this out and let me know if it works or not! Thanks.
I had a problem that audio was not played on iOS 13 Simulator in Xcode 11.5 while it was okay in Xcode SwiftUI preview and physical device.

AVAudioPlayer does not play audio file - swift

I know it seems quite straightforward, but in a weird way AVAudioPlayer does not play audio file. I have this code. It is not go through catch and still sound does not play. I've checked on physical device, simulator and also checked sound volume. But still I can't hear sound.
//in ViewController as a property
let soundEffect: AVAudioPlayer!
//in viewDidLoad
let path = Bundle.main.path(forResource: "success.mp3", ofType:nil)!
let url = URL(fileURLWithPath: path)
do {
soundEffect = try AVAudioPlayer(contentsOf: url)
soundEffect.prepareToPlay()
soundEffect.play()
} catch let error as NSError {
print(error.description)
}
I also tried let path = Bundle.main.path(forResource: "success", ofType:"mp3")! but it didn't make any difference.
Try making your AVAudioPlayer an instance variable. otherwise soundEffect is deallocated at the end of the do loop.

SWIFT : Incorrect argument label in call Xcode 7.3.1

import SpriteKit
import AVFoundation
class HGBackgroundMusic: SKScene {
var audioPlayer = AVAudioPlayer()
func getSoundReady() {
var plop = NSURL(fileURLWithPath:NSBundle.mainBundle().pathForResource("Plop", ofType: "mp3")!)
var audioPlayer = AVAudioPlayer()
audioPlayer = AVAudioPlayer(contentsOfURL: plop, error: nil)
audioPlayer.prepareToPlay()
}
func playSound() {
audioPlayer.play()
}
}
In the
error:nil
line, an error is coming up stating: Incorrect argument label in call(have 'contentsOfURL:error:', expected'contentsOfURL:fileTypeHint:'). So I replace "error" with "fileTypeHint", and that brings up another error stating: Call can throw, but is not marked with 'try' and the error is not handled. I cannot fix this though I have spent hours trying to find what to do to solve it.
Replace your arc4random call with arc4random_uniform.

How to play the same sound overlapping with AVAudioPlayer?

This code plays the sound when the button is tapped but cancels the previous if it is pressed again. I do not want this to happen I want the same sound to overlap when repeatedly pressed. I believe it might be due to using the same AVAudioPlayer as I have looked on the internet but I am new to swift and want to know how to create a new AVAudioPlayer everytime the method runs so the sounds overlap.
func playSound(sound:String){
// Set the sound file name & extension
let soundPath = NSURL(fileURLWithPath:NSBundle.mainBundle().pathForResource(sound, ofType: "mp3")!)
do {
//Preperation
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
} catch _{
}
do {
try AVAudioSession.sharedInstance().setActive(true)
}
catch _ {
}
//Play the sound
var error:NSError?
do{
audioPlayer = try AVAudioPlayer(contentsOfURL: soundPath)
}catch let error1 as NSError {
error = error1
}
audioPlayer.prepareToPlay()
audioPlayer.play()
}
To play two sounds simultaneously with AVAudioPlayer you just have to use a different player for each sound.
In my example I've declared two players, playerBoom and playerCrash, in the Viewcontroller, and I'm populating them with a sound to play via a function, then trigger the play at once:
import AVFoundation
class ViewController: UIViewController {
var playerBoom:AVAudioPlayer?
var playerCrash:AVAudioPlayer?
override func viewDidLoad() {
super.viewDidLoad()
playerBoom = preparePlayerForSound(named: "sound1")
playerCrash = preparePlayerForSound(named: "sound2")
playerBoom?.prepareToPlay()
playerCrash?.prepareToPlay()
playerBoom?.play()
playerCrash?.play()
}
func preparePlayerForSound(named sound: String) -> AVAudioPlayer? {
do {
if let soundPath = NSBundle.mainBundle().pathForResource(sound, ofType: "mp3") {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
try AVAudioSession.sharedInstance().setActive(true)
return try AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: soundPath))
} else {
print("The file '\(sound).mp3' is not available")
}
} catch let error as NSError {
print(error)
}
return nil
}
}
It works very well but IMO is not suitable if you have many sounds to play. It's a perfectly valid solution for just a few ones, though.
This example is with two different sounds but of course the idea is exactly the same for two identic sounds.
I could not find a solution using just AVAudioPlayer.
Instead, I have found a solution to this problem with a library that is built on top of AVAudioPlayer.
The library allows same sounds to be played overlapped with each other.
https://github.com/adamcichy/SwiftySound