AVAudioPlayer not playing mp3 sound - swift

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

Related

AVAudioPlayer does not play audio file - swift

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.

How to play the same sound overlapping with AVAudioPlayer?

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

Why can't I playback sound files recorded by AVAudioRecorder?

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...

Can play a sound effect on apple watch simulator now?

I want to play a sound when user press on the button on WKInterfaceController. Here is how I did in my project:
- Add a AVFoundation frame work to my watchkit app.
- Import AVFoundation on my WKInterfaceController
- Create 2 variable for audio session and player:
var audioSession:AVAudioSession!
var player:AVAudioPlayer!
- make 2 function for configure an audio session and configure Audio Player:
func configureAudioSession() {
self.audioSession = AVAudioSession.sharedInstance()
var categoryError:NSError?
var activeError:NSError?
// set category cho audio session
self.audioSession.setCategory(AVAudioSessionCategoryPlayback, error: &categoryError)
println("error: \(categoryError)")
// set active cho audio session
var success = self.audioSession.setActive(true, error: &activeError)
if !success {
println("error making audio session active :\(activeError)")
}
}
func configureAudioPlayer() {
// Lay song path
var songPath = NSBundle.mainBundle().pathForResource("Open Source - Sending My Signal", ofType: "mp3")
// Chuyen thanh URL
println("songpath: \(songPath)")
var songURL = NSURL(fileURLWithPath: songPath!)
println("songURL: \(songURL)")
//
var songError:NSError?
// Tao audioplayer
self.player = AVAudioPlayer(contentsOfURL: songURL!, error: &songError)
println("songerror:\(songError)")
self.player.numberOfLoops = 0
}
After that i finish my button press function like this:
#IBAction func startGameButtonPressed() {
self.configureAudioSession()
self.configureAudioPlayer()
self.player.play()
}
Every thing's working fine , I can saw the southPath although my button is working but I cannot hear the sound. I still use these steps on IOS app and it's working fine. May be we can't play a sound effect on Watchkit at this time? If we can, please help me to do that.
No. It is not possible to play sounds with WatchKit on the Apple Watch.
- Apple's WatchKit Evangelist
It is not currently possible to play sounds using the latest build of WatchKit.
I would suggest submitting a feature request.
YEs its possible to play a sound file in apple watch application.You need to add the sound file separately in apple watch application extension and the call the AVAudioPlayer to play the sound file.
e.g:
let path = NSBundle.mainBundle().pathForResource("coinFlip", ofType:"caf")
let fileURL = NSURL(fileURLWithPath: path!)
player = AVAudioPlayer(contentsOfURL: fileURL, error: nil)
player.prepareToPlay()
player.delegate = self
player.play()

Best / Proper way to play a short sound

I'm trying to play a short sound in my Swift app.
The sound I want to play :
is very short (less than five seconds) ;
is one of the system sound (ex: sms received) ;
will most likely be played multiple time during the life cycle of my application ;
can be fired two time in less than the sound length time (i.e. fire the first one and a second one is fired before the first finish playing) ;
In addition to this, I would like to :
hear the sound only if the application is active and the "silent mode" is off ;
make the phone vibrate (regardless if silent mode is on or off).
So far, here is what I have :
import AVFoundation
class SoundPlayer {
// Singleton
class var sharedInstance : SoundPlayer {
struct Static {
static let instance : SoundPlayer = SoundPlayer()
}
return Static.instance
}
// Properties
var error:NSError?
var audioPlayer = AVAudioPlayer()
let soundURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("sound", ofType: "wav")!) // Working
//let soundURL = NSURL(string:"/System/Library/Audio/UISounds/sms-received1.caf") // Working
//let soundURL = NSURL(fileURLWithPath: NSBundle(identifier: "com.apple.UIKit")!.pathForResource("sms-received1", ofType: "caf")!) // Not working (crash at runtime)
init() {
AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient, error: nil)
AVAudioSession.sharedInstance().setActive(true, error: nil)
audioPlayer = AVAudioPlayer(contentsOfURL: soundURL, error: &error)
if (error != nil) {
println("[SoundPlayer] There was an error: \(error)")
}
}
func playSound() {
if (audioPlayer.playing) {
audioPlayer.stop()
}
audioPlayer.play()
}
}
What I understand there are several ways to play a sound.
The two most common ways seems to be : AVAudioPlayer (like I did) and AudioToolbox.
From there, I'm asking myself three questions :
Which of those two is the most adapted (best / proper) for my situation ? (AVAudioPlayer is working correctly at the moment)
Are we allowed to play a system sound ? (Very small gain in size if in don't add my own sound to the project)
If so, is NSURL(string:"/System/Library/Audio/UISounds/sms-received1.caf") a good way to retrieve the sound ? Any better / proper solution ?
Is there a way to vibrate the phone at the same time the sound is fired ?