Playing a sound with AVAudioPlayer - ios

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()
}
}

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()
}
}

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")
}
}

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.

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)
}
}

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()
}
}

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")

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)
}
}
}

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()
}
}

Related

Ok so I'm new to Swift. I've been trying to make an audio player and the code just gives me this error. What can I do?

import UIKit
import AVFoundation
class AVAudioPlayer : NSObject {
}
class ViewController: UIViewController {
#IBAction func keyPressed(_ sender: UIButton) {
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
func playSound() {
let player: AVAudioPlayer?
guard let sound = Bundle.main.url(forResource: "C", withExtension: "wav") else { return }
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
player = try AVAudioPlayer(contentsOfURL: sound, fileTypeHint: AVFileType.wav.rawValue)
guard let player = player else { return }
func play() -> Bool {}
} catch let error {
print(error.localizedDescription)
}
Xcode gives me an error in this line player = try AVAudioPlayer(contentsOfURL: sound, fileTypeHint: AVFileType.wav.rawValue) saying that Argument passed to call that takes no arguments
Replace '(contentsOfURL: sound, fileTypeHint: AVFileType.wav.rawValue)' with '' and when I try to fix it, it gives me this error: Cannot assign value of type 'AVAudioPlayer.Type' to type 'AVAudioPlayer'. Can somebody help me? PS sorry for bold, Stack wouldn't let me post because it had "too much code in it".
After the help from Sweeper, my code looks like this:
import AVFoundation
class ViewController: UIViewController {
var player: AVAudioPlayer?
#IBAction func keyPressed(_ sender: UIButton) {
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
func playSound() {
guard let sound = Bundle.main.url(forResource: "C", withExtension: "wav") else { return }
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
player = try AVAudioPlayer
guard let player = player else { return }
func play() -> Bool {}
} catch let error {
print(error.localizedDescription)
}
As I was saying in the comments, now it gives me this error: Use of unresolved identifier 'player'
You need to provide init(contentsOf:) throws method to initialize the player. Here is the code you need:
class ViewController: UIViewController {
var player: AVAudioPlayer?
func playSound() {
guard let sound = Bundle.main.url(forResource: "C", withExtension: "wav") else { return }
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
player = try AVAudioPlayer(contentsOf: sound)
player?.play()
} catch let error {
print(error.localizedDescription)
}
}
}

How to play sound in customer class and recognize the end of sound play

I want play a mp3 file in the swift application in a separate class (not in the viewController class) and recognize the end of sound.
My code send an EXC_BAD_ACCESS in AppDelegate.swift.
Here my code:
UIViewController.swift
class ViewController: UIViewController, AVAudioPlayerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let soundM = soundManager()
soundM.loadFile("glass_ping", soundType: "mp3")
soundM.playNow()
soundManager.swift
import Foundation
import AVFoundation
var audioPlayer = AVAudioPlayer();
class soundManager: NSObject, AVAudioPlayerDelegate {
override init()
{
super.init();
print("hallo")
}
func playNow(){
audioPlayer.play()
}
func loadFile(_ soundName: String, soundType: String){
let sound = Bundle.main.path(forResource: soundName, ofType: soundType)
do{
audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: sound!))
audioPlayer.delegate = self
audioPlayer.prepareToPlay()
audioPlayer.rate = 2.0
//audioPlayer.numberOfLoops = 2
}catch{
print(error)
}
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
print("finish")
}
Any Idea?
Thanks
I found a very strange solution an Im not sure why it's works:
UIViewController.swift
import UIKit
import AVFoundation
class ViewController: UIViewController {
private var player: AudioPlayerComposition!
#IBOutlet weak var power: Visualizer!
override func viewDidLoad() {
super.viewDidLoad()
// Get URL to resouce, create audioPlayer
let audioPlayer = AVAudioPlayer();
player = AudioPlayer(player: audioPlayer)
//player.play()
AudioPlayer.swift
import Foundation
import AVFoundation
class AudioPlayer: NSObject, AVAudioPlayerDelegate {
private var player: AVAudioPlayer
init(player: AVAudioPlayer, view: Visualizer) {
self.player = player
super.init()
self.loadFile("test", soundType: "mp3")
}
func loadFile(_ soundName: String, soundType: String){
let sound = Bundle.main.path(forResource: soundName, ofType: soundType)
do {
self.player = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: sound!))
self.player.prepareToPlay()
self.player.play()
}catch{
print(error)
}
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
print ("Finish")
}
This is really working. But as mention no clue why?

How to fix Thread 1: EXC_BAD_ACCESS (code=1, address=0x58) xcode

I am trying to play some sound files with buttons but pressing the button throws me this error Thread 1: EXC_BAD_ACCESS (code=1, address=0x58) on line
audioPlayer.play()
I have looked for possible solutions and I can't find anything related to that error, the function of my code runs well until the print, this is my complete code.
import UIKit
import AVFoundation
class ViewController: UIViewController {
var track: String? = nil
var audioPlayer = AVAudioPlayer()
#IBAction func heavyButton(_ sender: Any) {
track = "H"
print("heavy machine gun \(track!)")
reproducirAudio(audio: track!)
audioPlayer.play()
}
func reproducirAudio(audio: String) {
do {
print("entro a la funcion de reproducir")
audioPlayer = try AVAudioPlayer(contentsOf: URL.init(fileURLWithPath: Bundle.main.path(forResource: audio, ofType: "mp3")!))
audioPlayer.prepareToPlay()
} catch {
print(error)
}
}
}
i found a solution, this is for iOS13
import UIKit
import AVFoundation
class ViewController: UIViewController {
var track: String? = nil
var audioPlayer: AVAudioPlayer?
#IBAction func heavyButton(_ sender: Any) {
track = "H"
print("heavy machine gun \(track!)")
reproducirAudio(audio: track!)
}
func reproducirAudio(audio: String) {
let path = Bundle.main.path(forResource: "\(audio).mp3", ofType:nil)!
let url = URL(fileURLWithPath: path)
do {
audioPlayer = try AVAudioPlayer(contentsOf: url)
audioPlayer?.play()
} catch {
// couldn't load file :(
}
}

Audio not playing in simulator

I have three buttons and I'm trying to get a sound to play with each button.
The sounds don't play on the simulator wondering what was going wrong in my code.
import UIKit
import AVFoundation
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func mmm_sound(sender: UIButton) {
playSound("mmm")
}
#IBAction func aww_sound(sender: UIButton) {
playSound("aww")
}
#IBAction func maniacal_sound(sender: UIButton) {
playSound("hah")
}
//sound function
func playSound(soundName: String)
{
let sound = NSURL(fileURLWithPath:NSBundle.mainBundle().pathForResource(soundName, ofType: "wav")!)
do{
let audioPlayer = try AVAudioPlayer(contentsOfURL:sound)
audioPlayer.prepareToPlay()
audioPlayer.play()
}catch {
print("Error getting the audio file")
}
}
}
You should make AVAudioPlayer as global variable as local variable of 'AVAudioPlayer' get deallocate before it plays, your code can like this
//at top
var audioPlayer = AVAudioPlayer()
func playSound(soundName: String)
{
let sound = NSURL(fileURLWithPath:NSBundle.mainBundle().pathForResource(soundName, ofType:"wav")!)
do{
audioPlayer = try AVAudioPlayer(contentsOfURL:sound)
audioPlayer.prepareToPlay()
audioPlayer.play()
}catch {
print("Error getting the audio file")
}
}

Swift : Player audio file from another class file

First of all, I just want to let you know I'm a newbie in iOS programming ;)
I would like to know if the following scenario is possible or which way I need to update my code to make it work.
I would like to play an audio file located in the player class file within the ViewController file.
I added the file "test.wav" to the root of project.
My problem
When I play the sound by tapping a button, the program can't find the sound file. I have the following error message:
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
Main swift file: ViewController.swift
import UIKit
import AVFoundation
class ViewController: UIViewController {
var player1: Player!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func playAudio(sender: AnyObject) {
player1.playAudioFile()
}
}
Class file: Player.swift
import Foundation
import AVFoundation
class Player {
// Variables
var vc: ViewController!
var audioFile: AVAudioPlayer!
// Initializer
init (){
}
// Methods
func playAudioFile() {
if audioFile.playing {
audioFile.stop()
} else {
audioFile.play()
}
}
// Intialize ViewController
init (vc:ViewController!) {
// Set path for the attack sound
let audioSnd = NSBundle.mainBundle().pathForResource("test", ofType: "wav")
let audioFileURL = NSURL(fileURLWithPath: audioSnd!)
do {
try audioFile = AVAudioPlayer(contentsOfURL: audioFileURL, fileTypeHint: nil)
audioFile.prepareToPlay()
} catch let err as NSError {
print(err.debugDescription)
}
}
}
More information
My program has a class "Player", with subclasses such as "Human" and "Monster".
By default, my class player has some audio files for attacks, dying, etc.
Under some conditions, the "player" can become a human or a monster and get custom attack and dying sounds.
Thanks a lot for your help! ;)
Why are you initializing you player with a viewController ? You dont need that.
Change the Player class to:
import Foundation
import AVFoundation
class Player {
// Variables
var audioFile: AVAudioPlayer!
// Initializer
init() {
// Set path for the attack sound
let audioSnd = NSBundle.mainBundle().pathForResource("test", ofType: "wav")
let audioFileURL = NSURL(fileURLWithPath: audioSnd!)
do {
try audioFile = AVAudioPlayer(contentsOfURL: audioFileURL, fileTypeHint: nil)
audioFile.prepareToPlay()
} catch let err as NSError {
print(err.debugDescription)
}
}
// Methods
func playAudioFile() {
if audioFile.playing {
audioFile.stop()
} else {
audioFile.play()
}
}
}
And your ViewController.swift to:
import UIKit
import AVFoundation
class ViewController: UIViewController {
var player1: Player!
override func viewDidLoad() {
super.viewDidLoad()
// Note, that you need to initialize the player1 variable
player1 = Player()
}
#IBAction func playAudio(sender: AnyObject) {
player1.playAudioFile()
}
}
Swift is functional programming, so it is way better to separate the audio operation and viewController into different file/class. Then they could be reused in any scenarios.
Audio part
import AVFoundation
class AudioPlayer {
// Singleton to keep audio playing anywhere
static let shared = AudioPlayer()
var player: AVAudioPlayer?
private init() {}
func play(url: URL) {
do {
try AVAudioSession.sharedInstance().setMode(.default)
try AVAudioSession.sharedInstance().setActive(true, options: .notifyOthersOnDeactivation)
player = try AVAudioPlayer(contentsOf: url)
guard let player = player else { return }
player.prepareToPlay()
player.play()
} catch {
print("error occurred")
}
}
}
ViewController
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func playAudio(sender: AnyObject) {
let audioSnd = NSBundle.mainBundle().pathForResource("test", ofType: "wav")
// don't use force unwrap
guard let audioFileURL = NSURL(fileURLWithPath: audioSnd) else { return }
// call the shared instance here
AudioPlayer.shared.play(url: url)
}
}

Resources