10

I have this code in a very simple, single view Swift application in my ViewController:

var audioPlayer = AVAudioPlayer()

@IBAction func playMyFile(sender: AnyObject) {

    let fileString = NSBundle.mainBundle().pathForResource("audioFile", ofType: "m4a")
    let url = NSURL(fileURLWithPath: fileString)
    var error : NSError?
    audioPlayer = AVAudioPlayer(contentsOfURL: url, error: &error)
    audioPlayer.delegate = self
    audioPlayer.prepareToPlay()
    if (audioPlayer.isEqual(nil)) {
        println("There was an error: (er)")
    } else {
        audioPlayer.play()
        NSLog("working")
    }

I have added import AVFoundation and audioPlayer is a global variable. When I execute the code, it does print "working", so it makes it through without errors but no sound is played. The device is not in silent.

Kenneth
  • 1,035
  • 1
  • 12
  • 26
  • what is the purpose of `audioPlayer.delete(self)`? – Patrick Goley Jul 17 '14 at 00:04
  • what is the purpose of `audioPlayer = AVAudioPlayer()` if you're just going to replace it later? – matt Jul 17 '14 at 00:07
  • never never never never never check "error" directly like that. Look to see if `audioPlayer` is nil. If it is, _then_ there is an error and you can check `error`. – matt Jul 17 '14 at 00:08
  • 1
    @matt - to make it a global variable to ensure that it is not removed from memory before playing the file when it runs the `playMyFile` method. I have removed it and simply changed it to a local variable but that did not fix the problem. – Kenneth Jul 17 '14 at 00:09
  • 2
    never never call `NSURL(string:` on a file path. Use `fileURLWithPath`, that's what it's for. – matt Jul 17 '14 at 00:10
  • The local variable would be far worse. My point is simply that setting the property to an actual audio player is just a waste of overhead. This is why you have nil as a placeholder. – matt Jul 17 '14 at 00:18

10 Answers10

21

There's so much wrong with your code that Socratic method breaks down; it will probably be easiest just to throw it out and show you:

var player : AVAudioPlayer! = nil // will be Optional, must supply initializer

@IBAction func playMyFile(sender: AnyObject?) {
    let path = NSBundle.mainBundle().pathForResource("audioFile", ofType:"m4a")
    let fileURL = NSURL(fileURLWithPath: path)
    player = AVAudioPlayer(contentsOfURL: fileURL, error: nil)
    player.prepareToPlay()
    player.delegate = self
    player.play()
}

I have not bothered to do any error checking, but the upside is you'll crash if there's a problem.

One final point, which may or may not be relevant: not every m4a file is playable. A highly compressed file, for example, can fail silently (pun intended).

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 1
    The app does not crash when running this code, but it does not play the audio file. I also tried it with a second, mp3, file. With the Music app playing in the background, running this method does stop the music, but doesn't play the audio in my app. – Kenneth Jul 17 '14 at 00:23
  • I assure you that this works on my machine (in my actual app). - Have you got an AVAudioSession set up? It seems hard to believe that this would matter, but it's the only missing piece of the puzzle. – matt Jul 17 '14 at 00:40
  • I can send you a small demo app if you like. I didn't set up an AVAudioSession so that's not the issue. – matt Jul 17 '14 at 00:48
  • Maybe your delegate is stopping the music? Maybe you're letting go of this view controller somehow? I assure you that it works when the code I've shown is the _only code in the app_ (except the template stuff generated automatically). – matt Jul 17 '14 at 00:49
  • The problem was in the audio file I was using. This code does work as long as there are no problems with the file. – Kenneth Jul 28 '14 at 22:23
  • 1
    Thanks for the report - I did mention that possibility (last paragraph of my answer). I've had it happen all too often! – matt Jul 28 '14 at 23:03
  • 1
    Hi Matt - I ran your code and it worked once I commented out the player.delegate = self line. I am just curious - why would that stop it from working? The error I got was that my view controller did not conform to AVAudioPlayerDelegate – lostinthebits Feb 13 '15 at 04:18
  • 2
    @lostinthebits Just ran into the same thing. You need to update your `ViewController` class definition to include `AVAudioPlayerDelegate`, like so: `class ViewController: UIViewController, AVAudioPlayerDelegate {` – Alex Coleman Feb 22 '15 at 19:40
  • @lostinthebits But that's a different question. The OP didn't show his class declaration so I am not concerned with his class declaration; I _assume_ that it conforms to AVAudioPlayerDelegate, since otherwise it would be impossible to set the player's delegate to `self` - obviously. – matt Feb 22 '15 at 21:37
13

Important that AvPlayer is class member and not in the given function, else it goes out of scope... :)

iHolm
  • 131
  • 1
  • 2
7

I had to declare a global player variable

var player: AVAudioPlayer!

and set it in viewDidLoad

   override func viewDidLoad() {
        super.viewDidLoad()
        player = AVAudioPlayer()
    }

Then I could play the audio file wherever like this:

    func playAudioFile(){
    do {
        if audioFileUrl == nil{
            return 
        }
           try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
           try AVAudioSession.sharedInstance().setActive(true)
           /* The following line is required for the player to work on iOS 11. Change the file type accordingly*/
           player = try AVAudioPlayer(contentsOf: audioFileUrl, fileTypeHint: AVFileType.m4a.rawValue)
           /* iOS 10 and earlier require the following line:
           player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3) */
           guard let player = player else { return }
           player.play()
        print("PLAYING::::: \(audioFileUrl)")
       }
    catch let error {
           print(error.localizedDescription)
       }
}

}

fullmoon
  • 8,030
  • 5
  • 43
  • 58
6

Here is a working snippet from my swift project. Replace "audiofile" by your file name.

    var audioPlayer = AVAudioPlayer()
    let audioPath = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("audiofile", ofType: "mp3"))
    audioPlayer = AVAudioPlayer(contentsOfURL: audioPath, error: nil)
    audioPlayer.delegate = self
    audioPlayer.prepareToPlay()
    audioPlayer.play()

You can download fully functional Swift Audio Player application source code from here https://github.com/bpolat/Music-Player

bpolat
  • 3,879
  • 20
  • 26
1

for some reason (probably a bug) Xcode can't play certain music files in the .m4a and the .mp3 format I would recommend changing them all to .wav files to get it to play

//top of your class
var audioPlayer = AVAudioPlayer

//where you want to play your sound
let Sound = NSURL(fileURLWithPath: Bundle.main.path(forResource: "sound", ofType: "wav")!)
    do {
        audioPlayer = try AVAudioPlayer(contentsOf: Sound as URL)
        audioPlayer.prepareToPlay()
    } catch {
        print("Problem in getting File")
    }
    audioPlayer.play()
Anonymous
  • 168
  • 1
  • 12
0

var audioPlayer = AVAudioPlayer()
var alertSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("KiepRongBuon", ofType: "mp3")!)
        AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, error: nil)
        AVAudioSession.sharedInstance().setActive(true, error: nil)
        var error:NSError?
        audioPlayer = AVAudioPlayer(contentsOfURL: alertSound, error: &error)
        audioPlayer.prepareToPlay()
        audioPlayer.play()
William Kane
  • 31
  • 1
  • 1
  • 3
0

I used the below code in my app and it works. Hope that is helpful.

var audioPlayer: AVAudioPlayer!
if var filePath = NSBundle.mainBundle().pathForResource("audioFile", ofType:"mp3"){

     var filePathUrl = NSURL.fileURLWithPath(filePath)
     audioPlayer = AVAudioPlayer(contentsOfURL: filePathUrl, error: nil)
     audioPlayer.play()
}else {
     println("Path for audio file not found")
}
0

In Swift Coding using Try catch, this issues will solve and play audio for me and my code below,

var playerVal = AVAudioPlayer()

         @IBAction func btnPlayAction(sender: AnyObject) {
                let fileURL: NSURL = NSURL(string: url)!
                    let soundData = NSData(contentsOfURL: fileURL)

                    do {
                        playerVal = try AVAudioPlayer(data: soundData!)
                    }
                    catch {
                        print("Something bad happened. Try catching specific errors to narrow things down",error)
                    }

                    playerVal.delegate = self
                    playerVal.prepareToPlay()

                    playerVal.play()

              }
Iyyappan Ravi
  • 3,205
  • 2
  • 16
  • 30
0

Based on @matt answer but little bit detailed 'cause original answer did not completely satisfied me.

import AVFoundation

class YourController: UIViewController {

  private var player : AVAudioPlayer?

  override func viewDidLoad() {
     super.viewDidLoad()

     prepareAudioPlayer()
  }

  @IBAction func playAudio() {

      player?.play()
  }
}

extension YourController: AVAudioPlayerDelegate {}

private extension YourController {

    func prepareAudioPlayer() {

        guard let path = Bundle.main.path(forResource: "you-audio", ofType:"mp3") else {
            return
        }
        let fileURL = URL(fileURLWithPath: path)
        do {
            player = try AVAudioPlayer(contentsOf: fileURL)
        } catch let ex {
            print(ex.localizedDescription)
        }
        player?.prepareToPlay()
        player?.delegate = self
    }
}
Aleksey Shevchenko
  • 1,159
  • 1
  • 11
  • 23
-1

swift 3.0:

 import UIKit
    import AVFoundation

    class ViewController: UIViewController
    {
        var audioplayer = AVAudioPlayer()

        @IBAction func Play(_ sender: Any)
        {
            audioplayer.play()
        }
        @IBAction func Pause(_ sender: Any)
        {
            if audioplayer.isPlaying
            {
                audioplayer.pause()
            }
            else
            {

            }
        }
        @IBAction func Restart(_ sender: Any)
        {
            if audioplayer.isPlaying
            {
                audioplayer.currentTime = 0
                audioplayer.play()
            }
            else
            {
                audioplayer.play()
            }

        }
        override func viewDidLoad()
        {
            super.viewDidLoad()

            do
            {
                audioplayer = try AVAudioPlayer(contentsOf:URL.init(fileURLWithPath:Bundle.main.path(forResource:"bahubali", ofType: "mp3")!))
                audioplayer.prepareToPlay()

                var audioSession = AVAudioSession.sharedInstance()

                do
                {
                    try audioSession.setCategory(AVAudioSessionCategoryPlayback)
                }

                catch
                {

                }
            }
            catch
            {
                print (error)
            }

        }
     }   
ronak patel
  • 400
  • 5
  • 17