Avqueueplayer in For loop - swift

I want to add the following method in for loop.
func playQuequeSounds(time:String){
let song1 = AVPlayerItem(URL: NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("estimatedTime", ofType: "mp3", inDirectory: "Audiofiles")!))
let song2 = AVPlayerItem(URL: NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(time, ofType: "mp3", inDirectory: "Audiofiles")!))
let song3 = AVPlayerItem(URL: NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("minutes", ofType: "mp3", inDirectory: "Audiofiles")!))
self.queueplayer = AVQueuePlayer(items: [song1,song2,song3])
self.queueplayer.actionAtItemEnd = AVPlayerActionAtItemEnd.Advance
self.queueplayer.play()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "playerDidFinishPlaying:", name: AVPlayerItemDidPlayToEndTimeNotification , object: song3)
}
i add the above method in viewWillApear
override func viewWillAppear(animated: Bool) {
voiceRouteTableView.reloadData()
NSNotificationCenter.defaultCenter().removeObserver(self)
for i in 0...voicesRoutes.count{
flag=false
self.playQuequeSounds(String(i+1))
while flag==false{
}
}
sleep(2)
}
The problem is that the loop runs very quicky and doesn't wait the avqueueplayer to finish the play. Add notification and change the code into the loop for waiting until the follow method call but the same problem.
func playerDidFinishPlaying(note: NSNotification) {
flag=true
}

Related

How to play several sound in a row

The goal is to play several sounds one after another (getReady -> nextExercise -> burpees).
The problem is that only the first one is being played
How it should work:
I call playGetReady() from WorkoutTabataViewController
I plays the first sound
After the first sound is finished, automatically "audioPlayerDidFinishPlaying()" is being called
It triggers "playNextSound()" func, which playing next sound
But audioPlayerDidFinishPlaying() is not being called. Or am I missing something and it should work differently?
class AudioPlayerManager: AVAudioPlayerDelegate {
var description: String
static let shared = AudioPlayerManager()
var audioPlayer: AVAudioPlayer?
var workoutVC: WorkoutTabataViewController?
var mainVC: MainTabataViewController?
var currentSound = 0
let urls: [URL]
init() {
self.description = ""
//First sound
let getReady = Bundle.main.path(forResource: "Get ready", ofType: "mp3")!
let urlGetReady = URL(fileURLWithPath: getReady)
//Second sound
let nextExercise = Bundle.main.path(forResource: "Next Exercise", ofType: "mp3")!
let urlNextExercise = URL(fileURLWithPath: nextExercise)
//Third sound
let burpees = Bundle.main.path(forResource: "Burpees", ofType: "mp3")!
let urlBurpees = URL(fileURLWithPath: burpees)
urls = [urlGetReady, urlNextExercise, urlBurpees]
}
func playGetReady() {
do {
audioPlayer = try AVAudioPlayer(contentsOf: urls[currentSound])
audioPlayer?.delegate = self
audioPlayer?.play()
} catch {
print(error)
}
}
func playNextSound() {
currentSound += 1
if currentSound < urls.count {
do {
audioPlayer = try AVAudioPlayer(contentsOf: urls[currentSound])
audioPlayer?.delegate = self
audioPlayer?.play()
} catch {
print(error)
}
}
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
if flag {
playNextSound()
}
}
}
Your audio manager class is not introspectable. Say #objc func audioPlayerDidFinishPlaying or, better, make it an NSObject.

How to make a video loop in Xcode swift 5?

I am trying to get a video background in my app and I have written the following code. It runs one time and then stops. How do I make the video repeat forever? Thanks in advance.
#IBOutlet weak var videoLayer: UIView!
override func viewDidLoad() {
super.viewDidLoad()
playBackgroundVideo()
}
func playBackgroundVideo(){
guard let path = Bundle.main.path(forResource: "City", ofType: "MOV") else {
return
}
let player = AVPlayer(url: URL(fileURLWithPath: path))
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.view.bounds
playerLayer.videoGravity = .resizeAspectFill
self.videoLayer.layer.addSublayer(playerLayer)
player.play()
}
#objc func playerItemDidReachEnd(notification: Notification) {
let p: AVPlayerItem = notification.object as! AVPlayerItem
p.seek(to: .zero)
}
}
Try adding a notification listener to trigger the playerItemDidReachEnd code.
You do this by involving a NotificationCenter.default.addObserver in your setup.
Did not test your code, but you want a setup like this example:
#IBOutlet weak var videoLayer: UIView!
var player: AVPlayer!
override func viewDidLoad()
{
super.viewDidLoad()
playBackgroundVideo()
}
func playBackgroundVideo()
{
guard let path = Bundle.main.path(forResource: "City", ofType: "MOV") else{ return }
player = AVPlayer(url: URL(fileURLWithPath: path))
let playerLayer = AVPlayerLayer(player: player)
//# add a Listener
NotificationCenter.default.addObserver( self,
selector: #selector(playerItemDidReachEnd),
name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
object: nil)
playerLayer.frame = self.view.bounds
playerLayer.videoGravity = .resizeAspectFill
self.videoLayer.layer.addSublayer(playerLayer)
player.play()
}
#objc func playerItemDidReachEnd(notification: Notification)
{
player.seek(to: CMTime.zero)
player.play()
}

AVPlayer ,black screen after video is over

i have black screen after video is over, but i would like to be redirect to another storyboard when video is over.
Could somebody help me with this.
Thanks you
import UIKit
import AVKit
import AVFoundation
class ViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
playVideo()
}
private func playVideo() {
guard let path = Bundle.main.path(forResource: "Kristinka", ofType:"m4v") else {
debugPrint("video.m4v not found")
return
}
let player = AVPlayer(url: URL(fileURLWithPath: path))
let playerController = AVPlayerViewController()
playerController.showsPlaybackControls = false
playerController.player = player
present(playerController, animated: true) {
player.play()
}
}
}
You need to detect when the item you're playing has reached the end. To do that, you can add an observer. For example:
func finishedVideo(_ notification: NSNotification) {
print("Animation did finish")
}
private func playVideo() {
guard let path = Bundle.main.path(forResource: "Kristinka", ofType:"m4v") else {
debugPrint("video.m4v not found")
return
}
let player = AVPlayer(url: URL(fileURLWithPath: path))
let playerController = AVPlayerViewController()
playerController.showsPlaybackControls = false
playerController.player = player
present(playerController, animated: true) {
NotificationCenter.default.addObserver(self,
selector: #selector(finishedVideo(_:)),
name: .AVPlayerItemDidPlayToEndTime,
object: player?.currentItem)
player.play()
}
}
And I dug this code up on this very related question. There's a lot of related/duplicate answers if you do a search.

How to make a function play different sounds in Swift

I have 10 different buttons and each button has a unique tag associated with it. All buttons are linked to the same IBAction. I have the function to play different different sounds according to the tag associated with the particular button that is clicked.
import AVFoundation
var myAudio: AVAudioPlayer!
let path = Bundle.main.path(forResource: "sound1", ofType: "wav")!
let url = URL(fileURLWithPath: path)
do {
let sound = try AVAudioPlayer(contentsOf: url)
myAudio = sound
sound.play()
} catch {
//
}
}
do like
#objc func yourbtnActionName(_ sender : UIButton){
switch sender.tag {
case 1:
commonSoundCode(name: "sound1")
break
case 2:
commonSoundCode(name: "yoursecondSoundname")
break
default:
break
}
}
then common method as
func commonSoundCode(name: String){
let path = Bundle.main.path(forResource: name, ofType: "wav")!
let url = URL(fileURLWithPath: path)
do {
let sound = try AVAudioPlayer(contentsOf: url)
myAudio = sound
sound.play()
} catch {
//
}
}
option 2
if your sound files are in the same sequence, for e.g (sound1.wav, sound2.wav......, sound10.wav) then call like
#objc func yourbtnActionName(_ sender : UIButton){
let path = Bundle.main.path(forResource: "sound\(sender.tag)", ofType: "wav")!
let url = URL(fileURLWithPath: path)
do {
let sound = try AVAudioPlayer(contentsOf: url)
myAudio = sound
sound.play()
} catch {
//
}
}
You need to simply play sounds according to the UIButton's tag.
#IBAction func playsound(_ sender: UIButton)
{
switch sender.tag
{
case 0:
//Sound for Button with tag=0
case 1:
//Sound for Button with tag=1
default:
//Default Sound
}
}
In the above code, add more cases according to your UIButton tags.
Please add some more code for a bit more clarity around your question.
import UIKit
//Mark: Do import AVFoundation is must here!
import AVFoundation
class ViewController: UIViewController {
//Mark: Create variable for AVAudioEngine! and AVAudioplayermode!
var engine: AVAudioEngine!
var audioPlayerNode : AVAudioPlayerNode!
//Mark: Create Variable for each tone as AVAudiofile!
var Cs:AVAudioFile!
var Ds:AVAudioFile!
var Es:AVAudioFile!
var Fs:AVAudioFile!
var Gs:AVAudioFile!
var As:AVAudioFile!
var Bs:AVAudioFile!
override func viewDidLoad() {
super.viewDidLoad()
// Mark: Load engine
engine = AVAudioEngine()
// Mark : Mention each sound
Cs = try? AVAudioFile(forReading: NSURL.fileURL(withPath:
Bundle.main.path(forResource: "C", ofType: "wav")!))
Ds = try? AVAudioFile(forReading: NSURL.fileURL(withPath:
Bundle.main.path(forResource: "D", ofType: "wav")!))
Es = try? AVAudioFile(forReading: NSURL.fileURL(withPath:
Bundle.main.path(forResource: "E", ofType: "wav")!))
Fs = try? AVAudioFile(forReading: NSURL.fileURL(withPath:
Bundle.main.path(forResource: "F", ofType: "wav")!))
Gs = try? AVAudioFile(forReading: NSURL.fileURL(withPath:
Bundle.main.path(forResource: "G", ofType: "wav")!))
As = try? AVAudioFile(forReading: NSURL.fileURL(withPath:
Bundle.main.path(forResource: "A", ofType: "wav")!))
Bs = try? AVAudioFile(forReading: NSURL.fileURL(withPath:
Bundle.main.path(forResource: "B", ofType: "wav")!))
}
//Mark: create function(playSound) for connect AVAudioEngine and AVAudioplayermode for playing audio when button clicked
func playSound(audioFile: AVAudioFile) {
audioPlayerNode = AVAudioPlayerNode()
if(audioPlayerNode.isPlaying){
audioPlayerNode.stop()
}
if(engine.isRunning){
engine.stop()
engine.reset()
}
engine.attach(audioPlayerNode)
engine.connect(audioPlayerNode, to: engine.mainMixerNode, format: audioFile.processingFormat)
audioPlayerNode.scheduleFile(audioFile, at: nil, completionHandler: nil)
// Start the audio engine
engine.prepare()
try! engine.start()
audioPlayerNode.play()
}
//Mark: create required button for actions to connect function(playSound) and mention each sound to button
#IBAction func btnC(_ sender: UIButton) {
playSound(audioFile: Cs)
}
#IBAction func btnD(_ sender: UIButton) {
playSound(audioFile: Ds)
}
#IBAction func btnE(_ sender: UIButton) {
playSound(audioFile: Es)
}
#IBAction func btnF(_ sender: UIButton) {
playSound(audioFile: Fs)
}
#IBAction func btnG(_ sender: UIButton) {
playSound(audioFile: Gs)
}
#IBAction func btnA(_ sender: UIButton) {
playSound(audioFile: As)
}
#IBAction func btnB(_ sender: UIButton) {
playSound(audioFile: Bs)
}
}

Create a function from code

How do I create a function from this code in swift3?
I have a button which is pressed then plays this sound "push"
How can it be simplified when there are lots of buttons? I don't want to add all codes to every button.
var myAudio = AVAudioPlayer()
// Add sound
do {
try myAudio = AVAudioPlayer(contentsOf: NSURL(fileURLWithPath:
Bundle.main.path(forResource: "push", ofType: "mp3")!) as URL)
} catch {
NSLog("No file!")
}
//call the sound
myAudio.play()
I made this change
func play(name : String){
do {
try myAudio = AVAudioPlayer(contentsOf: NSURL(fileURLWithPath:
Bundle.main.path(forResource: name, ofType: "mp3")!) as URL)
} catch {
NSLog("No file!")
}
}
#IBAction func buttonFirst(_ sender: UIButton) {
play(name: "push")
myAudio.play()
}
#IBAction func buttonSecond(_ sender: UIButton) {
play(name: "second")
myAudio.play()
}
I got this output:
2017-07-25 16:13:23.270349+0100 sound[1728:933024] [aqme] 254: AQDefaultDevice (173): skipping input stream 0 0 0x0
Is that a problem?
I think you forgot the prepare
var audioPlayer = AVAudioPlayer()
let sound = URL(fileURLWithPath: Bundle.main.path(forResource: "sound", ofType: "mp3")!)
try! AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
try! AVAudioSession.sharedInstance().setActive(true)
try! audioPlayer = AVAudioPlayer(contentsOf: sound)
audioPlayer.prepareToPlay()
audioPlayer.play()
You can use it in the following way
var myAudio : AVAudioPlayer?
func playSound(){
let path = Bundle.main.path(forResource: "push", ofType:"mp3")!
let url = URL(fileURLWithPath: path)
do {
let sound = try AVAudioPlayer(contentsOf: url)
self.myAudio = sound
sound.numberOfLoops = 1
sound.prepareToPlay()
sound.play()
} catch {
print("error loading file")
// couldn't load file :(
}
}
Furthermore you can use SwiftySound that lets you play sounds easily in Swift 3.
for example
Sound.play(file: "push.mp3")