ios – How begin AVPictureInPicture when video is paused

ios – How begin AVPictureInPicture when video is paused


I’ve AVPlayer with AVPictureInPictureController. Play video in app and film In Image works besides one state of affairs.
Concern is: I pause video in software and through swap to background isn’t PiP activate. What do I fallacious?

import UIKit
import AVKit
import AVFoundation

class ViewControllerSec: UIViewController,AVPictureInPictureControllerDelegate {
    var pipPlayer: AVPlayer!
    var avCanvas : UIView!
    var pipCanvas: AVPlayerLayer?
    var pipController: AVPictureInPictureController!
    var mainViewControler : UIViewController!
    var playerItem : AVPlayerItem!
    var videoAvasset : AVAsset!

    public func hyperlink(to parentViewController : UIViewController) {
        mainViewControler = parentViewController
        setup()
    }

    @objc func appWillResignActiveNotification(software: UIApplication) {
        pipController.startPictureInPicture()
    }

    non-public func setupAudio() {
        do {
            let session = AVAudioSession.sharedInstance()
            strive session.setCategory(.playback, mode: .moviePlayback)
            strive session.setActive(true)
        } catch {
            print("Audio session setup failed: (error.localizedDescription)")
        }
    }

    
    @objc func playerItemDidFailToPlayToEnd(_ notification: Notification) {
        if let error = notification.userInfo?[AVPlayerItemFailedToPlayToEndTimeErrorKey] as? Error {
            print("Didn't play to finish: (error.localizedDescription)")
        }
    }
    
    func setup() {
        setupAudio()
        // 1. Arrange AVPlayer
        guard let videoURL = URL(string: "https://demo.unified-streaming.com/k8s/options/steady/video/tears-of-steel/tears-of-steel.mp4/.m3u8") else { return }
        videoAvasset = AVAsset(url: videoURL)
        playerItem = AVPlayerItem(asset: videoAvasset)

        addPlayerObservers()
        pipPlayer = AVPlayer(playerItem: playerItem)

        // 2. Arrange AVPlayerLayer
        avCanvas = UIView(body: view.bounds)
        pipCanvas = AVPlayerLayer(participant: pipPlayer)
        guard let pipCanvas else { return }
        pipCanvas.body = avCanvas.bounds
        //pipCanvas.videoGravity = .resizeAspectFill
               
        mainViewControler.view.addSubview(avCanvas)
        avCanvas.layer.addSublayer(pipCanvas)
        
        
        // 3. Arrange AVPictureInPictureController
        if AVPictureInPictureController.isPictureInPictureSupported() {
            pipController = AVPictureInPictureController(playerLayer: pipCanvas)
            pipController?.delegate = self
            pipController?.canStartPictureInPictureAutomaticallyFromInline = true
        }
        
        let playButton = UIButton(body: CGRect(x: 20, y: 50, width: 100, top: 50))
        playButton.setTitle("Play", for: .regular)
        playButton.backgroundColor = .blue
        playButton.addTarget(self, motion: #selector(playTapped), for: .touchUpInside)
        mainViewControler.view.addSubview(playButton)

        let pauseButton = UIButton(body: CGRect(x: 140, y: 50, width: 100, top: 50))
        pauseButton.setTitle("Pause", for: .regular)
        pauseButton.backgroundColor = .pink
        pauseButton.addTarget(self, motion: #selector(pauseTapped), for: .touchUpInside)
        mainViewControler.view.addSubview(pauseButton)

        let pipButton = UIButton(body: CGRect(x: 260, y: 50, width: 150, top: 50))
        pipButton.setTitle("Begin PiP", for: .regular)
        pipButton.backgroundColor = .inexperienced
        pipButton.addTarget(self, motion: #selector(startPictureInPicture), for: .touchUpInside)
        mainViewControler.view.addSubview(pipButton)
        print("Error:(String(describing: pipPlayer.error?.localizedDescription))")
        
        // Observe software state modifications
        NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: nil) { [weak self] _ in
            guard let self = self else { return }
            if self.pipPlayer.fee == 0 {
                self.pipPlayer.play()
                pipController?.startPictureInPicture()
            }
        }

    func addPlayerObservers() {
         // Observe participant merchandise's standing
         playerItem?.addObserver(self, forKeyPath: "standing", choices: [.old, .new], context: nil)
         
         // Observe playback completion
         NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying(_:)), identify: .AVPlayerItemDidPlayToEndTime, object: playerItem)
     }

     // Observe participant standing modifications
     override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
         if keyPath == "standing" {
             if let statusNumber = change?[.newKey] as? NSNumber {
                 let standing = AVPlayer.Standing(rawValue: statusNumber.intValue)!
                 swap standing {
                 case .readyToPlay:
                     print("Participant is able to play")
                 case .failed:
                     print("Participant failed: (String(describing: playerItem?.error))")
                 case .unknown:
                     print("Participant standing is unknown")
                 @unknown default:
                     fatalError()
                 }
             }
         }
     }
     
     @objc func playerDidFinishPlaying(_ notification: Notification) {
         print("Video completed taking part in.")
     }
     
     deinit {
         // Clear up observers
         playerItem?.removeObserver(self, forKeyPath: "standing")
         NotificationCenter.default.removeObserver(self)
     }
    
    @objc func playTapped() {
        pipPlayer.play()
    }

    @objc func pauseTapped() {
        pipPlayer.pause()
    }
    
    @objc func startPictureInPicture() {
        if let pipController = pipController, !pipController.isPictureInPictureActive {
            pipController.startPictureInPicture()
        }
    }

    @objc func stopPictureInPicture() {
        if let pipController = pipController, pipController.isPictureInPictureActive {
            pipController.stopPictureInPicture()
        }
    }

    // MARK: - AVPictureInPictureControllerDelegate Strategies

    func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
        print("PiP will begin")
    }

    func pictureInPictureControllerDidStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
        print("PiP did begin")
    }

    func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, failedToStartPictureInPictureWithError error: Error) {
        print("Failed to start out PiP: (error.localizedDescription)")
        if let underlyingError = (error as NSError).userInfo[NSUnderlyingErrorKey] {
             print("Underlying error: (underlyingError)")
         }
    }

    func pictureInPictureControllerWillStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
        print("PiP will cease")
    }

    func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
        print("PiP did cease")
    }
}

I strive use observers with appWillResignActiveNotification to activate PiP. It’s name earlier than observer appDidEnterBackground however this additionally don’t clear up my drawback, additionally tryied to start out play video in observers after which activate PiP with the identical outcome.
I get error in occasion: Failed to start out PiP: Failed to start out image in image.

Leave a Reply

Your email address will not be published. Required fields are marked *