I am using AVPlayer to play online videos. It is working fine. Now the problem is, when I pop out from the view before the videos starts playing, the background process keeps running. And when the videos gets loaded, it starts playing in background.
Before dismiss view pause player
if player != nil {
player.pause()
player = nil
}
and also you need to pause player when your app goes to background
add this in your viewDidLoad
NotificationCenter.default.addObserver(self,
selector: #selector(applicationDidEnterBackground),
name: NSNotification.Name.UIApplicationDidEnterBackground,
object: nil)
add this in your viewController
#objc func applicationDidEnterBackground() {
if player != nil {
player.pause()
player = nil
}
}
By handling those both scenario you can stop player when you dismiss from that viewController also when your app goes into background
Hope this will help you
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if self.player != nil {
self.player.pause()
}
}
Related
I'm working on a music player in Swift. The user can play a track, pause the track, or move a slider to choose a place to start. These three functions work.
However, if a user plays a track, listens for 1:00, and hits pause: when they click play again, it will restart the track from 0:00 instead of respecting where they paused.
I am using AVAudioPlayer as a media player -- according to the documentation, .play() allows you to specify a start-point using atTime.
So I tried to use atTime and have it start where the slider is -- if a listener listens for 1:00, I want atTime to dynamically pick that up. I try to establish this time value in a var.
class MusicViewController: UIViewController {
// removed imports and viewdidload to condense
#IBAction func playDownload(_ sender: Any) {
// removed file download code to condense
do {
audioPlayer = try AVAudioPlayer(contentsOf: destinationUrl)
guard let player = audioPlayer else { return }
//here's where I try to capture a time value from the slider's progress
let checkTime = TimeInterval(Slider.value)
player.prepareToPlay()
player.play(atTime: checkTime)
} catch let error {
print(error.localizedDescription)
}
// updates slider with progress
Slider.value = 0.0
Slider.maximumValue = Float((audioPlayer?.duration)!)
audioPlayer.play()
timer = Timer.scheduledTimer(timeInterval: 0.0001, target: self, selector: #selector(self.updateSlider), userInfo: nil, repeats: true)
}
#IBAction func pause(_ sender: Any) {
if audioPlayer.isPlaying {
audioPlayer.pause()
} else {
audioPlayer.play()
}
}
#IBOutlet var Slider: UISlider!
#objc func updateSlider() {
Slider.value = Float(audioPlayer.currentTime)
print("Changing works")
}
}
So I am trying to capture progress and have .play respect that -- this code will run, but it does not work. No errors but after hitting play, it will go to the end of the track immediately now. No good.
I am new to Swift - any idea where I went wrong?
Hi I build a basic game with swift that has background music. The game has multiple image views. I have the music playing with with the code below. How do I stop the music if the user exits out of the app using the home button. as it is now the music continues to play even when the user presses the home button. The background music continues through out all image views which is what i want.
func playBackgroundMusic(thesong: String) {
let url = NSBundle.mainBundle().URLForResource(thesong, withExtension: nil)
guard let newURL = url else {
print("Could not find file: \(thesong)")
return
}
do {
backgroundMusicPlayer = try AVAudioPlayer(contentsOfURL: newURL)
backgroundMusicPlayer.numberOfLoops = -1
backgroundMusicPlayer.prepareToPlay()
backgroundMusicPlayer.play()
} catch let error as NSError {
print(error.description)
}
}
playBackgroundMusic("thesong.mp3")
You can use an observer in your controller like this:
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("pauseSong:"), name:UIApplicationDidEnterBackgroundNotification, object: nil)
And call this function when your controller detect when your app is running in background:
func pauseSong(notification : NSNotification) {
backgroundMusicPlayer.pause()
}
Then, when your app is opened again, add another observer to play the song:
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("playSong:"), name:UIApplicationWillEnterForegroundNotification, object: nil)
Then call this function:
func playSong(notification : NSNotification) {
backgroundMusicPlayer.play()
}
Hope it helps you ;)
You have to use this function in your controller:
func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
backgroundMusicPlayer.pause()
}
I have a parent view with a play button that instantiates an AVPlayerViewController object. If the user presses the player's default "Done" button, the player view disappears and the parent view works as expected. However, when playback finishes by reaching the end of the video, the player disappears but the parent view screen is unresponsive to button clicks. I don't understand because both scenarios are using the same callback to dismiss the player view.
Here is the code where I instantiate the AVPlayer and set up the two notifications for how the playback can be completed:
func playVideoLocally() {
// create player
let playerItem = AVPlayerItem(asset: AVAsset(URL: NSURL(string: media.url)!))
player = AVPlayer(playerItem: playerItem)
// create modal view with callback for done button
// This works fine
playerController = CustomAVPlayerViewController()
playerController.player = player
playerController.modalPresentationStyle = UIModalPresentationStyle.OverFullScreen
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "onLocalPlayCompletion:",
name: CustomAVPlayerViewController.viewWillDisappearNotification,
object: nil)
self.presentViewController(playerController, animated: true, completion: nil)
// create player completion callback
// This leads to unresponsive parent view
NSNotificationCenter.defaultCenter().addObserver(self, selector: "onLocalPlayCompletion:",
name: AVPlayerItemDidPlayToEndTimeNotification,
object: playerItem)
// play it
player.play()
}
Here is my onLocalPlayCompletion callback that both scenarios are calling:
func onLocalPlayCompletion(note: NSNotification) -> Void {
playerController.view.removeFromSuperview()
onCompletion()
}
I found the problem. The only reason why pressing "Done" wasn't affecting the parent view is because it's using a default AVPlayer action to dismiss itself. My attempt to dismiss the player from inside onLocalPlayCompletion(),
playerController.view.removeFromSuperview()
isn't correct, and in my case I replaced it with
self.dismissViewControllerAnimated(true, completion: nil)
which does what I want.
I am playing video using AVPlayer. When I go in background player is paused and when it is brought in foreground player is played. But still video is not appearing though it contains URL in its current Item. I am stuck and not getting and solution.Please help me to resolve. Thanks in advance.
Below code is used to play initially:-
let item1 = AVPlayerItem.init(URL: NSURL(string:path))
player = AVPlayer(playerItem: item1)
layer?.player = player;
player?.play()
Below code is used to pause and resume:-
func pausePlayerOnBackgroundAppearance()
{
if(player != nil)
{
player?.pause()
}
}
func resumePlayerOnForegroundAppearance()
{
if(player != nil)
{
player?.play()
}
}
If I am seeking some time to play video at some time where it was paused before then also it is not playing video
func pausePlayerOnBackgroundAppearance()
{
if(player != nil){
let currentItem:AVPlayerItem = player!.currentItem
currentTime = CMTimeGetSeconds(currentItem.currentTime())
player?.pause()
}
}
func resumePlayerOnForegroundAppearance()
{
if(player != nil){
player!.seekToTime(CMTimeMake(Int64(currentTime!), 1))
player?.play()
}
}
I'm developing a game with SpriteKit that can be paused during execution and can be resumed.
But I have a problem with applicationDidEnterBackground when the home button is pressed while the game is paused because when I resume the game the entities start moving immediately even though the game was paused before.
I cannot find a way to implement applicationDidEnterBackground and other related method in AppDelegate since there is no connection between that and my GameScene.swift
I'm actually pausing the entities with the code
entitiesLayerNode.paused = true
gameState = .GamePaused
EDIT:
I want to explicitly pause the entitiesLayerNode because I have other 'moving' nodes that I want to keep. To the problem is that with the suggestion given below that method pauses everything! I just need to pause that layer.
I think that problem is that I cannot access the entitiesLayerNode from the View Controller.
I generally use the snippet
let mainScene = scene as GameScene
mainScene.entitiesLayerNode.pause = true
But Xcode gives me an error that scene is an unresolved identifier.
Pretty much the same as here
AppDelegate:
func applicationWillResignActive(application: UIApplication) {
NSNotificationCenter.defaultCenter().postNotificationName("PauseGameScene", object: self)
}
GameSceneViewController:
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("pauseGameScene"), name: "PauseGameScene", object: nil)
}
func pauseGameScene() {
if self.skView.scene != nil {
self.skView.paused = self.skView.scene.paused = true
}
}