iosswiftvideoavkitpicture-in-picture

Close Picture in Picture video when user choses a new video to play


I'm using AVKit to show videos to a user.

When the user selects a video it is presented using the standard player from AVKit. This makes it fullscreen.

If the user elects to make it 'Picture in Picture' the user is able to continue using the rest of the application.

This means the user is able to choose another video to play, which indeed does play (in fullscreen) at the same time as the previous video which is still visible in picture in picture.

I'd like to close the first (PiP) video when the second video is selected, however, before launching the 2nd video I try to 'dismiss' the previous, but it doesn't work.

I think it's because it's being shown as a PiP so the AVPlayerViewController doesn't represent it anymore...

Is there a way to do this simply?

Playing a video with the (not working) attempt to kill the first video if the second is trying to be played:

func play(FileName filename: String, FileType type: String)
{
    if self.isVideoPlaying == YES
    {
       self.playerController!.dismiss(animated: YES, completion: { self.isVideoPlaying = NO ; self.play(FileName: filename, FileType: type) })

       return
    }

    self.isVideoPlaying = YES

    let path = Bundle.main.path(forResource: filename, ofType: type)

    let url = NSURL(fileURLWithPath: path!)

    let player = AVPlayer(url: url as URL)

...

Solution

  • Ok, here's how I solved it:

    1. Have a class property of 'isAlreadyPlaying: Bool' that you set when you play a video... however

    2. In the method where you 'play' the video and present the AVPlayerViewController with the (new) video, have this check at the beginning:

    
    if self.isAlreadyPlaying == YES
    {
         killVideoPlayer()
    
         DispatchQueue.main.asyncAfter(deadline: .now() + 1.5, execute: { self.play(FileName: filename, FileType: type) })
    
         return
    }
    
    ... Here you put the normal play / present code
    
    

    And in the 'killVideoPlayer()' method, have the property 'isAlreadyPlaying' set to NO / false.

    i.e.

    (Just for those who don't already know), here's the kill function:

    private func killVideoPlayer()
    {
        self.isAlreadyPlaying          = NO
    
        self.playerController?.player?.pause()
        self.playerController?.player  = nil
    
        let audioSession = AVAudioSession.sharedInstance()
    
        do
        {
            try audioSession.setActive(false, options: .notifyOthersOnDeactivation)
            try audioSession.setCategory(.soloAmbient)
        }
        catch
        {
            print("Audio session failed")
        }
    
        self.playerController?.dismiss(animated: YES, completion: 
        { 
            self.playerController = nil 
        })
    }