2017-02-17 150 views
0

我上传了一首歌曲到CloudKit。它采用CkAsset格式。因为我无法在iOS中使用标准CloudKit连接来获取网址。我使用javascript获取它(CloudKit允许通过网络直接连接来获取网址)。问题是我可以通过链接在VLC或任何其他媒体播放器上流式传输音乐。但是,当我在AvPlayer上尝试它时。它不起任何作用。我将链接作为字符串,然后将其转换为NSURL。Stream Audio与Avplayer不兼容

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() 

回答

0

尝试创建一个“AVAsset”并异步加载它。观察播放器的状态,如准备好,失败等,并基于开始播放。

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()) 
     } 

    } 
+0

我觉得问题是,当我们写audioPath时,我们可以声明类型。但是,我不能这样做的网址。除了你的代码对我来说太复杂了,我无法弄清楚。 –