0.5 C
New York
Sunday, February 23, 2025

ios – How begin AVPictureInPicture when video is paused


I’ve AVPlayer with AVPictureInPictureController. Play video in app and film In Image works besides one scenario.
Problem is: I pause video in utility and through swap to background is just not PiP activate. What do I improper?

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(utility: UIApplication) {
        pipController.startPictureInPicture()
    }

    non-public func setupAudio() {
        do {
            let session = AVAudioSession.sharedInstance()
            attempt session.setCategory(.playback, mode: .moviePlayback)
            attempt 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("Did not 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 = .crimson
        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 utility 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 begin 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 attempt 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 begin play video in observers after which activate PiP with the identical consequence.
I get error in occasion: Failed to begin PiP: Failed to begin image in image.

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles