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.
Related
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!
I am trying to play a 30 second preview of a Spotify song using AVAudioPlayer. The url to the mp3 file looks like this: https://p.scdn.co/mp3-preview/4f5fa753f8e814c51c718bf34bbc594bf55ef5b2
Here is my code to play this song:
trackObj.previewURL = NSURL(fileURLWithPath:"https://p.scdn.co/mp3-preview/4f5fa753f8e814c51c718bf34bbc594bf55ef5b2")
// set up the audio player
if trackObj.previewURL != nil {
do {
try previewPlayer = AVAudioPlayer(contentsOfURL: trackObj.previewURL)
previewPlayer.prepareToPlay()
previewPlayer.play()
} catch _ {}
}
This does not do anything. The song does not begin to play at all.
AVAudioPlayer is not for remote URLs. Use AVPlayer instead.
Try this,
var aSongURL: String = String(format: " https://p.scdn.co/mp3-preview/4f5fa753f8e814c51c718bf34bbc594bf55ef5b2")
// NSLog(#"Song URL : %#", aSongURL);
var aPlayerItem: AVPlayerItem = AVPlayerItem(URL: NSURL(string: aSongURL)!)
var anAudioStreamer: AVPlayer = AVPlayer(playerItem: aPlayerItem)
anAudioStreamer.play()
Avoid syntax mistake if any because i have type here
hope this will help :)
I have a subclass of SKSpriteNode called 'backgroundMusic' that consists of a SKSpriteNode and a AVAudioPlayer file. The objective is to completely delete 'backgroundMusic' after i instantiate it. I try to do :
backgroundMusic.removeFromParent()
but it only removes the SKSpriteNode and not the AVAudioPlayer.
The main issue is that inside of this subclass, I call a bunch of functions within other functions, and when i try to empty the subclass by:
backgroundMusic = nil
the process of calling all the functions still is occurring and causes issues when i re-instantiate it. What i believe will work is if I delete 'backgroundMusic' completely, which will stop the function calling process, and then later re-instantiate it when i need to, it should work fine with no issues. How can I do this?
EDIT I tried:
self.delete(backgroundMusic)
and it crashed the application. Should I use this? If so how?
This happened because you havent configure Audio Session
Some code for playing:
import AVFoundation
var audioPlayer = AVAudioPlayer()
func playAudio() {
// Set the sound file name & extension
let alertSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("Flip 02", ofType: "wav")!)
// Preperation
try! AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, withOptions: AVAudioSessionCategoryOptions.MixWithOthers)
try! AVAudioSession.sharedInstance().setActive(true)
// Play the sound
do {
try audioPlayer = AVAudioPlayer(contentsOfURL: alertSound)
audioPlayer.prepareToPlay()
audioPlayer.play()
} catch {
print("there is \(error)")
}
}
Details from the docs:
AVAudioSessionCategoryOptionMixWithOthers
Mixes audio from this session with audio from other active sessions.
Valid only if the session category is
AVAudioSessionCategoryPlayAndRecord or AVAudioSessionCategoryPlayback.
(Implicit if the session category is AVAudioSessionCategoryAmbient.)
If you activate your session while using this option, your app’s audio
will not interrupt audio from other apps (such as the Music app). If
not using this option (or a category that is implicitly mixable),
activating your session will interrupt other nonmixable sessions.
To stop you can do:
do {
try AVAudioSession.sharedInstance().setActive(false)
} catch let error as NSError {
print(error.localizedDescription)
}
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
This is how I defined myrecorder and myplayer
var myrecorder:AVAudioRecorder!
var myplayer : AVAudioPlayer!
This is the code to setup myrecorder in the viewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
filepath = "\(getDocumentsDirectory())/001.caf"
print(filepath)
try! session.setCategory(AVAudioSessionCategoryPlayAndRecord)
//define settings
let recordSettings: [String: AnyObject] = [
AVFormatIDKey: NSNumber(unsignedInt: kAudioFormatMPEG4AAC),
AVEncoderAudioQualityKey : AVAudioQuality.Medium.rawValue,
AVSampleRateKey: 44100.0,
AVNumberOfChannelsKey: 2,
]
myrecorder = try! AVAudioRecorder(URL: NSURL(fileURLWithPath: filepath), settings: recordSettings)
myrecorder.delegate = self
myrecorder.prepareToRecord()
}
And I have buttons to control record and stop and I got the file 001.caf. I can playback the sound file but I think the file is not good enough.
#IBAction func Play() {
try! myplayer = AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: filepath))
myplayer.volume = 0.5
myplayer.play()
print("Playing...")
}
The playback is successful without any error or crash. With only one problem, it doesn't have any sound when playing.
I assume that I'd missed something in the recording phase but I couldn't locate it. Please help.
The issue is with the AVAudioPlayer that is instantiated in this line.
try! myplayer = AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: filepath))
This instance myplayer will get deallocated as soon as the play function completes.
Instantiate the AVAudio player in another function, such as Viewdidload, so that it sticks around even after the control leaves the play function.
Ok, finally I found the problem.
YOU CAN'T USE AVAudioSessionCategoryPlayAndRecord.
When recording, you had to use AVAudioSessionCategoryRecord and when playback you use AVAudioSessionCategoryPlayback. And you set the session back and forth when playback and record.
AVAudioSessionCategoryPlayAndRecord is used when playback and recording are needed in the same time, like when you do voice chat...