简体   繁体   中英

Stream Audio is not working with Avplayer

I uploaded a song to CloudKit. It is in CkAsset format. Because i can't fetch the web url with standard CloudKit connection in iOS. I'm fetching it with javascript (CloudKit allows to fetch web url with direct connection via web). The problem is i can stream the music on VLC or any other media player via link. However, when i try it on AvPlayer. It doesn't play anything.I got the link as string and then turn it in to NSURL.

    let a = webView.stringByEvaluatingJavaScript(from: "myVar")
    print(a!)
    let url : NSString = a! as NSString
    let urlStr : NSString = url.addingPercentEscapes(using: String.Encoding.utf8.rawValue)! as NSString
    let searchURL : NSURL = NSURL(string: urlStr as String)!
    print(searchURL)
    /*https://cvws.icloud-content.com/B/AVHgxc_-X3u9H5xK684KmUQrzDqp/$%7Bf%7D?o=Apgif1Giyg-lwRiNre2KJYl-5EhUAiL1m1OgE3-osxpxexWD7YGjCAOFCoQLRv8sGUglywu2tGr-OgfGtDZ15k0&v=1&x=3&a=BbLB0UptOX3bA-k6OQ&e=1487341935&k=_&fl=&r=0f83571c-d168-4743-b38b-0e808baa0a1a-1&ckc=iCloud.com.emreonder.ogun-dalka-music&ckz=_defaultZone&p=61&s=OuE127GKlo_0EIZ6y5t49gMv0qM 
     */
    let playerItem = AVPlayerItem(url: searchURL as URL)
    player = AVPlayer(playerItem: playerItem)
    let playerLayer:AVPlayerLayer = AVPlayerLayer(player: player)
    self.view.layer.addSublayer(playerLayer)
    self.player.play()

Try by creating an "AVAsset" and load it asynchronously. Observe the status of player like ready, failed etc and based on that start playing.

func initializePlayer() {
        //audio session for handling interuptions - Done Appdelegate
        /*
         1. Create Asset (Asset represent a single media), AVAsset -> AVAssetTrack
         2. Resource properties like metadata, duration etc are loaded from asset, but if taken syncrn will block so use async
         */

        let audioPath = Bundle.main.path(forResource: "big_buck_bunny", ofType: "mp4")
        let resourceUrl = URL(fileURLWithPath: audioPath!)
        let asset = AVAsset(url: resourceUrl)

        let playableKey = "playable"



        //        addObserver(self, forKeyPath: #keyPath(AVPlayerItem.rate), options: [.new, .initial], context: &audioPlayerInterfaceViewControllerKVOContext)
        //        addObserver(self, forKeyPath: #keyPath(AVPlayerItem.status), options: [.new, .initial], context: &audioPlayerInterfaceViewControllerKVOContext)

        // Load the "playable" property

        asset.loadValuesAsynchronously(forKeys: [playableKey]) { [unowned self] in

            var error: NSError? = nil

            let status = asset.statusOfValue(forKey: playableKey, error: &error)

            switch status {

            case .loaded:
                debugPrint("Sucessfuly loaded")
                self.playerItem = AVPlayerItem(asset: asset)

                self.playerItem?.addObserver(self, forKeyPath: #keyPath(AVPlayerItem.status), options: [.old, .new], context: &audioPlayerInterfaceViewControllerKVOContext)
                self.playerItem?.addObserver(self, forKeyPath: #keyPath(AVPlayerItem.duration), options: [.new, .initial], context: &audioPlayerInterfaceViewControllerKVOContext)
                self.player = AVPlayer(playerItem: self.playerItem)
                self.player.addObserver(self, forKeyPath: #keyPath(AVPlayer.rate), options: [.new,.initial], context: &audioPlayerInterfaceViewControllerKVOContext)
                let interval = CMTimeMake(1, 1)
//                self.player.volume = 0.5
                self.timeObserveToken = self.player.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main) { [unowned self] time in
                    let timeElapsed = Float(CMTimeGetSeconds(time))
                    UIView.animate(withDuration: 1.5, animations: {
                        if self.userActionEnabled {
                            self.durationSlider.setValue(Float(timeElapsed), animated: true)
                        }

                    })
                    if self.userActionEnabled {
                        self.startTimeLabel.text = self.createTimeString(time: timeElapsed)
                    }
                }

                break

                // Sucessfully loaded. Continue processing.

            case .failed:
                self.showErrorAlert(errorString: "Failed to load")
                debugPrint("failed")
                break

                // Handle error

            case .cancelled:
                self.showErrorAlert(errorString: "Failed to load")
                debugPrint("Cancelled")
                break

                // Terminate processing

            default:
                debugPrint("Error occured")
                self.showErrorAlert(errorString: "Failed to load")
                break

                // Handle all other cases

            }

        }
    }

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {

        guard context == &audioPlayerInterfaceViewControllerKVOContext else {
            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)

            return
        }

        if keyPath == #keyPath(AVPlayerItem.status) {

            let status: AVPlayerItemStatus

            if let statusNumber = change?[.newKey] as? NSNumber {

                status = AVPlayerItemStatus(rawValue: statusNumber.intValue)!

            } else {

                status = .unknown

            }

            // Switch over status value

            switch status {

            case .readyToPlay:
                player.play()
                break

                // Player item is ready to play.

            case .failed:
                showErrorAlert(errorString: "Failed to load")
                break

                // Player item failed. See error.

            case .unknown:
                showErrorAlert(errorString: "Failed to load")
                break

                // Player item is not yet ready.

            }

        }

        if keyPath == #keyPath(AVPlayerItem.duration) {
            let newDuration: CMTime
            if let newDurationAsValue = change?[NSKeyValueChangeKey.newKey] as? NSValue {
                newDuration = newDurationAsValue.timeValue
            }
            else {
                newDuration = kCMTimeZero
            }

            let hasValidDuration = newDuration.isNumeric && newDuration.value != 0
            let newDurationSeconds = hasValidDuration ? CMTimeGetSeconds(newDuration) : 0.0
            let currentTime = hasValidDuration ? Float(CMTimeGetSeconds((player.currentTime()))) : 0.0

            durationSlider.maximumValue = Float(newDurationSeconds)

            durationSlider.value = currentTime

            nextBtn.isEnabled = hasValidDuration

            playPauseBtn.isEnabled = hasValidDuration

            previousBtn.isEnabled = hasValidDuration

            durationSlider.isEnabled = hasValidDuration

            startTimeLabel.isEnabled = hasValidDuration
            startTimeLabel.text = createTimeString(time: currentTime)

            endTimeLabel.isEnabled = hasValidDuration
            endTimeLabel.text = createTimeString(time: Float(newDurationSeconds))
        }

        if keyPath == #keyPath(AVPlayer.rate) {
            // Update `playPauseButton` image.

            let newRate = (change?[NSKeyValueChangeKey.newKey] as? NSNumber)?.doubleValue

            let buttonImageName = newRate == 1.0 ? "Pause" : "Play"

            let buttonImage = UIImage(named: buttonImageName)

            playPauseBtn.setImage(buttonImage, for: UIControlState())
        }

    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM