74

I'm trying to play a sound with AVAudioPlayer but it won't work.

Edit 1: Still doesn't work.

Edit 2: This code works. My device was in silent mode.

import UIKit
import AVFoundation

class ViewController: UIViewController {

    var audioPlayer = AVAudioPlayer()

    override func viewDidLoad() {
        super.viewDidLoad()

        var alertSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("button-09", ofType: "wav"))
        println(alertSound)

        var error:NSError?
        audioPlayer = AVAudioPlayer(contentsOfURL: alertSound, error: &error)
        audioPlayer.prepareToPlay()
        audioPlayer.play()
    }
}
Kuldeep
  • 4,466
  • 8
  • 32
  • 59
user3722523
  • 1,740
  • 2
  • 15
  • 27
  • 2
    Instead of passing "`nil`" to the error parameter, why not pass something in and find out what the error actually is? – Michael Dautermann Jun 24 '14 at 18:13
  • the error contains nil – user3722523 Jun 24 '14 at 19:32
  • I'm practically using the exact same code as you for an osx application, and it all works except for the error code seems to be throwing some type of error itself: "fatal error: unexpectedly found nil while unwrapping an Optional value" which leads me to believe that there is something wrong with the error declaration. I don't know a lot about error in swift, but is this something you've run into before? – GregarityNow Feb 26 '15 at 14:58
  • @Uzebeckatrente - Check that you are not using NSURL(string:...). This returns nil for some reason in some circumstances. You should be using NSURL(fileURLWithPath:...) for file locations. – djb Feb 27 '15 at 18:55
  • @djb it's the NSError that's giving me issues, rather than the NSURL, I believe. – GregarityNow Feb 28 '15 at 02:36
  • 9
    hahaha... kudos for silent mode! – animal_chin May 05 '15 at 11:48
  • @djb NSURL(string:) it is for web resources only (web links) and NSURL(fileURLWithPath:) it is for local resource files (documents folder) – Leo Dabus Nov 27 '15 at 00:37

8 Answers8

63

Made modification to your code:

import UIKit
import AVFoundation

class ViewController: UIViewController {

    var audioPlayer = AVAudioPlayer()

    override func viewDidLoad() {
        super.viewDidLoad()

        var alertSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("button-09", ofType: "wav"))
        println(alertSound)

        // Removed deprecated use of AVAudioSessionDelegate protocol
        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()
    }

}

Swift 3 and Swift 4.1:

import UIKit
import AVFoundation

class ViewController: UIViewController {
    private var audioPlayer: AVAudioPlayer?

    override func viewDidLoad() {
        super.viewDidLoad()

        let alertSound = URL(fileURLWithPath: Bundle.main.path(forResource: "button-09", ofType: "wav")!)
        print(alertSound)

        try! AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
        try! AVAudioSession.sharedInstance().setActive(true)

        try! audioPlayer = AVAudioPlayer(contentsOf: alertSound)
        audioPlayer!.prepareToPlay()
        audioPlayer!.play()
    }
}
eharo2
  • 2,553
  • 1
  • 29
  • 39
vladof81
  • 26,121
  • 9
  • 38
  • 41
  • 1
    Hi, I'm trying to add sound to my program using about the same code and it is crashing. Where exactly do u put the audio file? In the assets folder or..? – blue Sep 21 '14 at 17:53
  • 2
    @skyguy, you may drag the sound file to your project and select the proper target to add. – vladof81 Sep 22 '14 at 19:10
  • any ideas on how to use it for pls or remote mp3 files? – danielsalare Sep 26 '14 at 20:42
  • @edse for remote mp3 file, initialize your alertSound like `var alertSound = NSURL(string: "http://my-file-url.com/song.mp3")` – Ruben Martinez Jr. Sep 28 '14 at 00:40
  • Will this work for streaming? I was trying the following with a pls ulr http://stackoverflow.com/questions/26075618/swift-radio-streaming-avplayer – danielsalare Sep 28 '14 at 01:35
  • I just tried this with a remote mp3 file and a pls file but it doesn't play any sound. If I use a local file works perfectly. – danielsalare Sep 28 '14 at 15:56
  • 1
    "The AVplayer doesn't provide support for streaming, you can with AVPlayer http://stackoverflow.com/questions/3635792/play-audio-from-internet-using-avaudioplayer – houguet pierre Dec 17 '14 at 15:26
  • 2
    Do I have to create a new instance of ``AVAudioPlayer`` for each sound file I will play? – Michael May 18 '15 at 19:06
  • Anyone else with some weird issue as mine, "just not working after copy pasting the code, ensure proper location and import of your files in the build phase" and the code above should thereafter work – Johhn Jul 29 '19 at 20:07
36

As per Swift 2 the code should be

var audioPlayer : AVAudioPlayer!

func playSound(soundName: String)
{
    let coinSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(soundName, ofType: "m4a")!)
    do{
        audioPlayer = try AVAudioPlayer(contentsOfURL:coinSound)
        audioPlayer.prepareToPlay()//there is also an async version
        audioPlayer.play()
    }catch {
        print("Error getting the audio file")
    }
}
Estevex
  • 791
  • 8
  • 17
  • 20
    You should make audioPlayer an instance variable somewhere. This code will have it deallocated immediately after calling .play() and you won't hear a thing. – scrrr Mar 27 '16 at 20:38
  • The app will also experience a slight lag because it needs to load the file and prepare the player all at once. – AppreciateIt Jun 21 '16 at 23:20
23

Your audio play will be deallocated right after viewDidLoad finishes since you assign it to a local variable. You need to create a property for it to keep it around.

rdelmar
  • 103,982
  • 12
  • 207
  • 218
12

The solution is for AudioPlayer which has play/pause/stop button in the navigation bar as bar button items

In Swift 2.1 you can use the below code

import UIKit
import AVFoundation

class ViewController: UIViewController {

    var player:AVAudioPlayer = AVAudioPlayer()

    override func viewDidLoad() {
            super.viewDidLoad()

            let audioPath = NSBundle.mainBundle().pathForResource("ARRehman", ofType: "mp3")
            var error:NSError? = nil
            do {
                player = try AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: audioPath!))
            }
            catch {
                print("Something bad happened. Try catching specific errors to narrow things down")
            }

        }

    @IBAction func play(sender: UIBarButtonItem) {
        player.play()

    }


    @IBAction func stop(sender: UIBarButtonItem) {
        player.stop()
        print(player.currentTime)
        player.currentTime = 0
    }


    @IBAction func pause(sender: UIBarButtonItem) {

        player.pause()
    }


    @IBOutlet weak var sliderval: UISlider!


    @IBAction func slidermov(sender: UISlider) {

        player.volume = sliderval.value
        print(player.volume)
    }

}
Naishta
  • 11,885
  • 4
  • 72
  • 54
7

This will work.....

import UIKit
import AVFoundation

class ViewController: UIViewController {

    var ding:AVAudioPlayer = AVAudioPlayer()

    override func viewDidLoad() {
        super.viewDidLoad()

        prepareAudios()
        ding.play()
    }

    func prepareAudios() {

        var path = NSBundle.mainBundle().pathForResource("ding", ofType: "mp3")
        ding = AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: path!), error: nil)
        ding.prepareToPlay()
    }
}
Chetan Prajapati
  • 2,249
  • 19
  • 24
  • 2
    _"This will work"_ But why it will work? Please explain what's wrong with OP and how you resolved it so that future users can understand the concept behind it. – Prudhvi Apr 22 '15 at 05:27
2

Use This Function to make sound in Swift (You can use this function where you want to make sound.)

First Add SpriteKit and AVFoundation Framework.

import SpriteKit
import AVFoundation
func playEffectSound(filename: String){
     runAction(SKAction.playSoundFileNamed("\(filename)", waitForCompletion: false))
}// use this function to play sound

playEffectSound("Sound File Name With Extension")
// Example :- playEffectSound("BS_SpiderWeb_CollectEgg_SFX.mp3")
Raksha Saini
  • 604
  • 12
  • 28
  • 1
    This may "work", but it does not preload audio and my result in negative performance when first executed – Ray Nov 22 '15 at 15:56
2

This is a pretty old question, but I did not see an answer that worked with Swift 3.0 so I modernized the code and added some safety checks to prevent crashes.

I also took the approach of pulling the playing part out into its own function to help with re-use for anyone coming across this answer.

import UIKit
import AVFoundation

class ViewController: UIViewController {
    var audioPlayer: AVAudioPlayer?

    override func viewDidLoad() {
        super.viewDidLoad()

        play(for: "button-09", type: "wav")
    }

    func play(for resource: String, type: String) {
        // Prevent a crash in the event that the resource or type is invalid
        guard let path = Bundle.main.path(forResource: resource, ofType: type) else { return }
        // Convert path to URL for audio player
        let sound = URL(fileURLWithPath: path)
        do {
            audioPlayer = try AVAudioPlayer(contentsOf: sound)
            audioPlayer?.prepareToPlay()
            audioPlayer?.play()
        } catch {
            // Create an assertion crash in the event that the app fails to play the sound
            assert(false, error.localizedDescription)
        }
    }
}
CodeBender
  • 35,668
  • 12
  • 125
  • 132
2

Swift 4.2 onwards, AudioSession category setup options have been changed. (Try following code for Swift 4.2 onwards)

import UIKit
import AVFoundation


class ViewController: UIViewController {


    var audioPlayer: AVAudioPlayer?

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


    func prepareAudioSession() -> Void {
        do {
            try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, mode: AVAudioSession.Mode.default, options: AVAudioSession.CategoryOptions.defaultToSpeaker)
            try AVAudioSession.sharedInstance().setActive(true)

            prepareAudioPlayer()

        } catch {
            print("Issue with Audio Session")
        }
    }


    func prepareAudioPlayer() -> Void {

        let audioFileName = "test"
        let audioFileExtension = "mp3"

        guard let filePath = Bundle.main.path(forResource: audioFileName, ofType: audioFileExtension) else {
            print("Audio file not found at specified path")
            return
        }

        let alertSound = URL(fileURLWithPath: filePath)
        try? audioPlayer = AVAudioPlayer(contentsOf: alertSound)
        audioPlayer?.prepareToPlay()
    }


    func playAudioPlayer() -> Void {
        audioPlayer?.play()
    }


    func pauseAudioPlayer() -> Void {
        if audioPlayer?.isPlaying ?? false {
            audioPlayer?.pause()
        }
    }


    func stopAudioPlayer() -> Void {
        if audioPlayer?.isPlaying ?? false {
            audioPlayer?.stop()
        }
    }

    func resetAudioPlayer() -> Void {
        stopAudioPlayer()
        audioPlayer?.currentTime = 0
        playAudioPlayer()
    }

}
Krunal
  • 77,632
  • 48
  • 245
  • 261