Can't play file from documents in AVAudioPlayer - ios

I have a file on documents folder of app and I want to play it.
if NSFileManager.defaultManager().fileExistsAtPath(pathString) {
let url = NSURL(fileURLWithPath:pathString, isDirectory: false)
do {
let player = try AVAudioPlayer(contentsOfURL:url)
player.prepareToPlay()
player.play()
}
catch let error as NSException {
print(error)
}
catch {}
}
There is a file on file system and I checked its existence. Also all lines in do block are executed. There is neither exception nor error and still no sound is played. What are possible problems and how can I solve them?

You should make audioPlayer an instance variable global. This code will have it deallocated immediately after calling .play()
class ViewController: UIViewController {
var audioPlayer = AVAudioPlayer()
override func viewDidLoad() {
super.viewDidLoad()
if NSFileManager.defaultManager().fileExistsAtPath(pathString){
let url = NSURL(fileURLWithPath:pathString, isDirectory: false)
AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, error: nil)
AVAudioSession.sharedInstance().setActive(true, error: nil)
var error:NSError?
audioPlayer = AVAudioPlayer(contentsOfURL: url, error: &error)
audioPlayer.prepareToPlay()
audioPlayer.play()
}
}
}

Related

Multiple Audio Files In One ViewController With Button

Want to play multiple audio files in the same ViewController. When a user clicks on Button1 the file1.mp3 should be loaded into ViewController and when user hit play same should play and for button2 file2.mp3 should load and play.
I know how to do this for a single file but for multiple files I have to create ViewController again and again which is so hard. This is my code for single file
#IBAction func buttonPressed(_ sender: UIButton) {
if player.isPlaying {
player.stop()
sender.setImage(UIImage(named:"play.png"),for: .normal)
} else {
player.delegate = self
player.play()
player.numberOfLoops = 107
sender.setImage(UIImage(named:"pause.png"),for: .normal)
}
}
do {
let audioPlayer = Bundle.main.path(forResource: "chalisa", ofType: "mp3")
try player = AVAudioPlayer(contentsOf: NSURL(fileURLWithPath: audioPlayer!) as URL)
}catch {
//ERROR
}
You can use Tableview List all songs Name and Play Button use to Multiple audio files use in one viewcontroller
import AVFoundation
//MARK:- Variable Declaration
var player: AVAudioPlayer?
func playMusic() {
guard let url = Bundle.main.url(forResource: "chalisa", withExtension: "mp3") else { return }
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
/* iOS 10 and earlier require the following line:
player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3) */
guard let player = player else { return }
player.play()
} catch let error {
print(error.localizedDescription)
}
}

Swift 2 - AVAudioPlayer not playing audio

I'm trying to play a sound with an AVAudioPlayer, but it doesn't play. I tried both a device (iPhone 6s) and the simulator. I'm not getting any errors and it logs it played. When I set a breakpoint before audioPlayer.play() and step over it plays for a few seconds and stops then. My code:
let soundURL = NSBundle.mainBundle().URLForResource("test", withExtension: "mp3")
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
try AVAudioSession.sharedInstance().setActive(true)
if let soundURL = soundURL {
let audioPlayer = try AVAudioPlayer(contentsOfURL: soundURL)
audioPlayer.volume = 1
audioPlayer.delegate = self
audioPlayer.prepareToPlay()
print(audioPlayer.duration)
audioPlayer.play()
print("PLAYED")
}
}catch {
print("Error getting the audio file")
}
Here is an example that will work. I am not sure where, in relation to the rest of your code, you have the code that you've shown above. Make sure your device volume is not on silent and is turned up...
//declare these as instance variables
var AudioURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("FileName", ofType: "mp3")!)
var AudioPlayer = AVAudioPlayer()
//inside viewDidLoad establish your AVAudioSession and configure the AudioPlayer with the contents of URL
override func viewDidLoad() {
super.viewDidLoad()
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
//print("AVAudioSession Category Playback OK")
do {
try AVAudioSession.sharedInstance().setActive(true)
//print("AVAudioSession is Active")
} catch let error as NSError {
print(error.localizedDescription)
}
} catch let error as NSError {
print(error.localizedDescription)
}
do {
try AudioPlayer = AVAudioPlayer(contentsOfURL: AudioURL, fileTypeHint: nil)
} catch {
print("errorin do-try-catch")
}
}
//play audio
#IBAction func playAudio(sender: AnyObject){
AudioPlayer.play()
}

AVAudioPlayer not playing mp3 file

I have run this app on my simulator as well as my phone and with multiple mp3 files however I cannot get sound to output from the app. I have included the mp3 file in the supported files. I am honestly lost as to what to do next. I receive no errors however there is no audio.
#IBAction func play (sender: AnyObject){
func sharedInstance() {
AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, error: nil)
AVAudioSession.sharedInstance().setActive(true, error: nil)
var audioPlayer = AVAudioPlayer()
var song = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("pingpong", ofType: "mp3")!)
println(song)
var error:NSError?
audioPlayer = AVAudioPlayer(contentsOfURL: song, error: &error)
audioPlayer.prepareToPlay()
audioPlayer.play()
}
sharedInstance()
}
Just make your var audioPlayer = AVAudioPlayer() global for your class like shown in below code:
And I have modified your code to make it safe:
import UIKit
import AVFoundation
class ViewController: UIViewController {
var audioPlayer = AVAudioPlayer()
#IBAction func play (sender: AnyObject){
var categoryError: NSError?
if AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, error: &categoryError) {
println("AVAudioSession Category Playback OK")
var activateError: NSError?
if AVAudioSession.sharedInstance().setActive(true, error: &activateError) {
println("AVAudioSession is Active")
var song = NSBundle.mainBundle().URLForResource("we_cant_Stop", withExtension: "mp3")!
var error:NSError?
audioPlayer = AVAudioPlayer(contentsOfURL: song, error: &error)
audioPlayer.play()
} else if let activateError = activateError {
println(activateError.description)
}
} else if let categoryError = categoryError {
println(categoryError.description)
}
}
}
This is working fine.

iOS AVAudioPlayer - how to set file path to the pathForResource

i want to play small mp3 file when button is clicked. but not sure how to set the mp3 file in setPathForResources
Here My Code
import UIKit
import AVFoundation
class PlaySoundsViewController: UIViewController {
var coinSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("/sounds/superman", ofType: "mp3")!)
var audioPlayer = AVAudioPlayer()
#IBOutlet weak var PlaySlow: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func PlaySlowAction(sender: UIButton) {
audioPlayer.play()
}
I have added the sounds folder to the project using just drag and drop. but when i click button im getting this error.
audioPlayer.play() Thread 1: EXC_BAD_ACCESS(Code=1,address=0x1c)
You don't need the sounds/ in your path. Just the filename. e.g.
var coinSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("superman", ofType: "mp3")!)
Also fileURLWithPath takes a URL, not a string. You need to convert your NSBundle.mainBundle().pathForResource("superman", ofType: "mp3") to a string first using NSURL(string:).
This is the full setup:
let path = NSBundle.mainBundle().pathForResource("superman", ofType:"mp3")
let fileURL = NSURL(fileURLWithPath: path)
player = AVAudioPlayer(contentsOfURL: fileURL, error: nil)
player.prepareToPlay()
player.delegate = self
player.play()
You missed a couple necessary steps in your "PlaySlowAction" method:
#IBAction func PlaySlowAction(sender: UIButton) {
// if the audioPlayer hasn't been set to any sound file yet,
// load it up...
if(audioPlayer.data == nil)
{
var error:NSError?
audioPlayer = AVAudioPlayer(contentsOfURL: coinSound, error: &error)
if let actualError = error {
println("An Error Occurred: \(actualError)")
}
}
audioPlayer.prepareToPlay()
audioPlayer.play()
}

AVAudioPlayer produces lag despite prepareToPlay() in Swift

Playing a very short sound (~0.5s) produces a hiccup (like a lag) in my SpriteKit iOS game programmed in Swift. In other questions, I read that I should prepareToPlay() the sound, which I did.
I even used a variable (soundReady) to check if the sound is prepared before playing it. I also re-prepare the sound whenever it is finished playing (audioPlayerDidFinishPlaying()). Here are the relevant parts of the code:
class GameScene: SKScene, AVAudioPlayerDelegate {
var splashSound = NSURL()
var audioPlayer = AVAudioPlayer()
var soundReady = false
override func didMoveToView(view: SKView) {
let path = NSBundle.mainBundle().pathForResource("plopSound", ofType: "m4a")
splashSound = NSURL(fileURLWithPath: path)
audioPlayer = AVAudioPlayer(contentsOfURL: splashSound, error: nil)
audioPlayer.delegate = self
soundReady = audioPlayer.prepareToPlay()
}
func playSound(){
if(soundReady){
audioPlayer.play()
soundReady = false
}
}
func audioPlayerDidFinishPlaying(player: AVAudioPlayer!, successfully flag: Bool){
//Prepare to play after Sound finished playing
soundReady = audioPlayer.prepareToPlay()
}
}
I have no idea where I've gone wrong on this one. I feel like I have tried everything (including, but not limited to: only preparing once, preparing right after playing, not using a variable, but just prepareToPlay()).
Additional information:
The sound plays without delay.
How quickly the sound is played after the last finish does not seem to impact the lag.
I ran into this same problem and played the sound in the backgroundQueue.
This is a good example: https://stackoverflow.com/a/25070476/586204.
let qualityOfServiceClass = QOS_CLASS_BACKGROUND
let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
dispatch_async(backgroundQueue, {
audioPlayer.play()
})
Just adding a Swift 3 version of the solution from #brilliantairic.
DispatchQueue.global().async {
audioPlayer.play()
}
When I called play multiple times it would cause bad access. I believe the player is being deallocated since this is not thread safe. I created a serial queue to alleviate this problem.
class SoundManager {
static let shared = SoundManager()
private init() {
try? AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
try? AVAudioSession.sharedInstance().setActive(true)
}
private let serialQueue = DispatchQueue(label: "SoundQueue", qos: .userInitiated)
private var player: AVAudioPlayer?
static func play(_ sound: Sound) {
shared.play(sound)
}
func play(_ sound: Sound) {
guard let url = Bundle.main.url(forResource: sound.fileName, withExtension: "mp3")
else { return }
do {
try serialQueue.sync {
self.player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3)
DispatchQueue.main.async {
self.player?.play()
}
}
} catch let error as NSError {
print("error: \(error.localizedDescription)")
}
}
}

Resources