AVFragmentedAssetMinder не работает на устройстве iPhone, но работает на симуляторе

#ios #avfoundation #avplayer

Вопрос:

У нас есть фрагментированные данные о фильмах, которые поступают через WebSecureSocket (wss://). Мы записываем это в файл temp.mp4 и одновременно воспроизводим фрагменты, которые были записаны в файл. Итак, для этого мы использовали AVFragmentedAsset и AVFragmentedAssetMinder. Он работает так, как и ожидалось в симуляторе. Но в устройстве не обновляется продолжительность ресурса и не публикуется .Уведомление об обмене данными avassetdurationdid. Не уверен, в чем может быть проблема. Уже потратил 2 дня на выяснение этого, но безуспешно. Может кто-нибудь помочь мне с этим, пожалуйста,

Реализация..

 public class WssPlayerSource: WebSocketDelegate {
    
    static let ASSET_MINDER = AVFragmentedAssetMinder()
    
    private let socketClient: WebSocketStreamingClient
    private var tempMovieFile:FileHandle? = nil
    private var startedPlay = false
    private var fragmentedAsset: AVFragmentedAsset? = nil
    
    let player = AVPlayer()
    
    init(withUrl url: URL) {
        socketClient = WebSocketStreamingClient(wssUrl: url)
        socketClient.delegate = self
        do {
            self.tempMovieFile = try getTemporaryMovieFileWriter()
        }catch {
            print("Error opening file")
        }
        
        NotificationCenter.default.addObserver(self, selector: #selector(onVideoUpdate), name: .AVAssetDurationDidChange, object: nil)
        socketClient.connect()
    }
    
    // Socket delegate
    public func didReceive(event: WebSocketEvent, client: WebSocket) {
        switch event {
        case .binary(let data):
            
            self.tempMovieFile?.write(data)
           
            if !startedPlay {
                startedPlay = true
                DispatchQueue.global().async { [weak self] in
                    self?.didReceivedInitialData()
                }
            }
            break;
        default:
            break;
        }
    }
    
    func didReceivedInitialData() {
        fragmentedAsset = AVFragmentedAsset(url: getTemporaryMovieFile()!)
        fragmentedAsset?.loadValuesAsynchronously(forKeys: ["duration", "containsFragments", "canContainFragments"], completionHandler: {
            WssPlayerSource.ASSET_MINDER.mindingInterval = 1
            WssPlayerSource.ASSET_MINDER.addFragmentedAsset(self.fragmentedAsset!)
            
            self.player.replaceCurrentItem(with: AVPlayerItem(asset: self.fragmentedAsset!))
            self.player.play()
        })
    }
    
    @objc
    func onVideoUpdate() {
        print("Video duration updated..")
        // This is not called in device.. but in simulator it works as expected
    }
    
    func stop() {
        socketClient.forceDisconnect()
        NotificationCenter.default.removeObserver(self)
        if let asset = self.fragmentedAsset {
            WssPlayerSource.ASSET_MINDER.addFragmentedAsset(asset)
        }
    }
}
 

И

 class ViewController: UIViewController {
    
    @IBOutlet var playerView:PlayerView!
    
    private static let SOCKET_URL = "wss://..."
    
    private var playerSource:WssPlayerSource? = nil
    private var playerLayer:AVPlayerLayer? = nil
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.playerSource =  WssPlayerSource(withUrl: URL(string: ViewController.SOCKET_URL)!)
        self.playerLayer = AVPlayerLayer(player: self.playerSource!.player)
        self.playerLayer?.videoGravity = .resize
        self.playerView.layer.addSublayer(self.playerLayer!)
    }
}
 

Комментарии:

1. Покажите, как создается и поддерживается экземпляр PlayerController. Как мы можем быть уверены, что он не исчезнет до того, как появятся уведомления? Мне кажется, что это может быть слабая ссылка. (Плюс использование sleep(2) весьма подозрительно.)

2. @мэтт, спасибо, что разбираешься в этом. Для удобства чтения я завернул код PlayerController для этого поста внутрь. Это создается и управляется в ViewController. sleep(2) это не проблема, я просто добавил его, чтобы в файле было доступно больше данных до инициализации ресурса.

3. Так это не твой настоящий код?

4. @мэтт, это был настоящий код. Только то, что я разместил требуемую часть. Теперь я обновил полный код. Пожалуйста, взгляните