I want to run multiple audios in a loop. So I want to stop the execution of loop until the completion of running audio.
I have tried semaphores but no luck. Should I have to run it on main thread or what?
#IBAction func btnPlayAudiosClicked(_ sender: Any) {
for each in Constants.audioNames{
semaphore.wait()
txtStatus.text = "Playing audio " + each
AudioManager.shared.playSound(audioName: each)
semaphore.signal()
}
}
import AVFoundation
class YourClass: ..., AVAudioPlayerDelegate {
var player: AVAudioPlayer?
var yourURLStrings:[String] = []
override func viewDidLoad() {
self.playSound(position: 0)
}
func playSound(position: Int) {
let firstURL = yourURLStrings[position]
do {
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: url, fileTypeHint: AVFileType.mp3.rawValue)
/* iOS 10 and earlier require the following line:
player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3) */
//Set delegate to self so we can execute delegate `AVAudioPlayerDelegate` functions
player.delegate = self
guard let player = player else { return }
player.play()
} catch let error {
print(error.localizedDescription)
}
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
self.yourURLStrings.remove(at: 0)
if(yourURLStrings.count > 0) {
self.playSound(position: 0)
}
}
}
Related
I have added background music to my app using the following code:-
Now I am trying to add audio controls to my app using the following methods, but after I click on another view controller and come back to the main view controller the play button is not working. Any help will be highly appreciated Thanks!
var toggleState = 1
var music: AVAudioPlayer!
override func viewDidLoad() {
super.viewDidLoad()
playMusic()
}
func playMusic() {
if let musicURL = Bundle.main.url(forResource: "Adding", withExtension: "mp3") {
if let audioPlayer = try? AVAudioPlayer(contentsOf: musicURL) {
music = audioPlayer
music.numberOfLoops = -1
music.play()
}
}
}
#IBAction func playButtonPressed(_ sender: Any) {
if (toggleState == 1) {
music.pause()
toggleState = 2
}
else {
music.play()
toggleState = 1
}
}
I want to make it so that a button can be clicked, which will start repeatedly playing a system sound over and over (without overlapping the sounds) until the button is clicked again - so essentially, the button will toggle the repeated playing of an audio services system sound on/off.
If anyone would know how to do this I would greatly appreciate it.
Thanks
To do this use an AVAudioplayer with infinite repeat, and then pause/play it when button is pressed.
First make a audioPlayer variable, outside of any function:
var audioPlayer : AVAudioPlayer!
Then initialise the audioPlayer inside of viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
guard let url = Bundle.main.path(forResource: "myOwnSound", ofType: "wav") else { //your own file name AND extension type of course
print("file not found")
return
}
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
try AVAudioSession.sharedInstance().setActive(true)
try audioPlayer = AVAudioPlayer(contentsOf: URL(string: url)!)
audioPlayer!.prepareToPlay()
audioPlayer.numberOfLoops = -1
} catch let error as NSError {
print("error while initialising sound: \(error)")
}
}
Then inside a function linked to your button, in my case I named that function buttonPressed:
#IBAction func buttonPress(_ sender:AnyObject){
if audioPlayer.isPlaying {
audioPlayer.pause()
}
else {
audioPlayer.play()
}
}
You can use AVFoundation and AVAudioPlayer to manage music and
sound inside you application
Import following
import AVFoundation
Create a property of AVAudioPlayer to manage play/stop and add following code inside the scope of your music button
var player : AVAudioPlayer?
#IBAction func openListAction(_ sender: UIButton) {
// moveToGame()
if sender.isSelected {
sender.isSelected = false
player?.stop()
}
else {
sender.isSelected = true
let bundle = Bundle.init(for: self.classForCoder)
let path = bundle.path(forResource: "soundFileName", ofType : "soundFileExtension")! //.mp3, .caf etc
let url = URL(fileURLWithPath : path)
do {
player = try AVAudioPlayer(contentsOf: url)
player?.play()
} catch {
print ("Error to load music")
}
}
}
I am trying to have a button that will play a sound when pushed.
The app I have has 6 buttons (with 6 different sounds). I only have one listed because I am trying to get one button to work correctly before doing the rest. I know the button is working (from the print command at the bottom), but it is not playing the sound.
import UIKit
import AVFoundation
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
var player : AVAudioPlayer?
#IBAction func buttonOne(_ sender: Any) {
func playSound() {
let url = Bundle.main.url(forResource: "drinking", withExtension: "mp3")!
do {
player = try AVAudioPlayer(contentsOf: url)
guard let player = player else { return }
player.prepareToPlay()
player.play()
} catch let error as NSError {
print(error.description)
}
}
print("Anakin: IT IS WORKING!")
}
}
Is it printing any error?
Can you try doing this?
let path = Bundle.main.path(forResource: "FILE NAME WITH EXTENSION", ofType:nil)!
let url = URL(fileURLWithPath: path)
do {
let sound = try AVAudioPlayer(contentsOf: url)
sound.play()
} catch {
// couldn't load file :(
}
My final game over scene has an SKTransition back to the Main Menu. I am able to make a song play for the final game over scene, but I would like the song to continue into my Main Menu.
Here is a copy of the code I have at the moment.
import Foundation
import SpriteKit
import AVFoundation
class SceneThree: SKScene {
var game = SKSpriteNode()
var new: AVAudioPlayer?
override func didMove(to view: SKView) {
self.backgroundColor = SKColor.black
playSound()
}
func playSound() {
let url = Bundle.main.url(forResource: "new", withExtension: "caf")!
do {
new = try AVAudioPlayer(contentsOf: url)
guard let new = new else { return }
new.prepareToPlay()
new.play()
} catch let error {
print(error.localizedDescription)
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let gameScene = GameScene(fileNamed: "GameScene")
gameScene?.scaleMode = .aspectFill
self.view?.presentScene(gameScene!, transition: SKTransition.fade(withDuration: 4.5))
}
When you change scene the old one will get destroyed, which includes your AVPlayer property.
You can create a helper class for your music to avoid this.
class MusicManager {
static let shared = MusicManager()
var audioPlayer = AVAudioPlayer()
private init() { } // private singleton init
func setup() {
do {
audioPlayer = try AVAudioPlayer(contentsOf: URL.init(fileURLWithPath: Bundle.main.path(forResource: "music", ofType: "mp3")!))
audioPlayer.prepareToPlay()
} catch {
print (error)
}
}
func play() {
audioPlayer.play()
}
func stop() {
audioPlayer.stop()
audioPlayer.currentTime = 0 // I usually reset the song when I stop it. To pause it create another method and call the pause() method on the audioPlayer.
audioPlayer.prepareToPlay()
}
}
When your project launches just call the setup method
MusicManager.shared.setup()
Than from any where in your project you can say
MusicManager.shared.play()
to play the music.
To than stop it just call the stop method
MusicManager.shared.stop()
For a more feature rich example with multiple tracks check out my helper on GitHub
https://github.com/crashoverride777/SwiftyMusic
Hope this helps
I am trying to play a sound in my iOS app (written in Swift 2) using AVFoundation. I had it working with no issues with the previous version of Swift. I am using Xcode 7.0. I am not sure what the issue is and cannot find any additional info for Swift 2 regarding playing sounds. Here's my code for the sound part:
import AVFoundation
class ViewController: UIViewController {
var mySound = AVAudioPlayer()
override func viewDidLoad() {
super.viewDidLoad()
mySound = self.setupAudioPlayerWithFile("mySound", type:"wav")
mySound.play()
}
func setupAudioPlayerWithFile(file:NSString, type:NSString) -> AVAudioPlayer {
var path = NSBundle.mainBundle().pathForResource(file, ofType:type)
var url = NSURL.fileURLWithPath(path!)
var error: NSError?
var audioPlayer:AVAudioPlayer?
audioPlayer = AVAudioPlayer(contentsOfURL: url, error: &error)
return audioPlayer!
}
}
I am getting this error but have a feeling there maybe some other issue:
'NSString' is not implicitly convertible to 'String'; did you mean to use 'as' to explicitly convert?
Like Leo said
You need to implement do try catch error handling.
Here is another example of some code that will run sound when a button is pressed.
import UIKit
import AVFoundation
class ViewController: UIViewController {
#IBAction func play(sender: AnyObject) {
player.play()
}
#IBAction func pause(sender: AnyObject) {
player.pause()
}
var player: AVAudioPlayer = AVAudioPlayer()
override func viewDidLoad() {
super.viewDidLoad()
let audioPath = NSBundle.mainBundle().pathForResource("sound", ofType: "mp3")!
do {
try player = AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: audioPath))
} catch {
// Process error here
}
}
}
I hope this helps!
You need to implement do try catch error handling. Try like this:
func setupAudioPlayerWithFile(file: String, type: String) -> AVAudioPlayer? {
if let url = NSBundle.mainBundle().URLForResource(file, withExtension: type) {
do {
return try AVAudioPlayer(contentsOfURL: url)
} catch let error as NSError {
print(error.localizedDescription)
}
}
return nil
}