2016-06-12 44 views
0

我需要连续播放一些音频,因此需要使用AVQueuePlayer来实现此目的。我加载音频在它:在AVQueuePlayer中异步加载AVURLAsset会扰乱订单 - iOS

for (NSInteger i = row ; i<_messagesArray.count ; i++) 
    { 
     _urlString = ((PFFile*)(_messagesArray[i][@"messageFile"])).url; 

     AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:[NSURL URLWithString:_urlString] options:nil]; 
     NSArray *keys = @[@"playable"]; 


     AVPlayerItem *item = [AVPlayerItem playerItemWithAsset:asset]; 

     // Subscribe to the AVPlayerItem's DidPlayToEndTime notification. 
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(itemDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:item]; 



     if (_queuePlayer == nil) 
     { 
      _queuePlayer = [[AVQueuePlayer alloc] initWithPlayerItem:item]; 

     } 
     else 
     { /*This loads Async*/ 
      [asset loadValuesAsynchronouslyForKeys:keys completionHandler:^() { 
       [_queuePlayer insertItem:item afterItem:nil]; 
      }]; 
     } 

    } 

[_queuePlayer play]; 

现在的问题是,因为我通过Async加载从URL资产(见上面的代码else条件),音频文件在我AVQueuePlayer顺序不一样的,在_messagesArray

例如网址: _messagesArray = audioURL1 , audioURL2, audioURL3

然后由于异步,取其先加载,进入AVQueuePlayer第一

AVQueuePlayer = audio2 (from URL2) , audio1 (from URL1) , audio3 (from URL3)

请建议一个解决方案来维持我的播放器的顺序。

谢谢。

+0

当您插入时,您可以根据项目URL检查_messageArray的位置在哪里? – Larme

+0

@Larme可以请你详细说一下吗?不明白 – hyd00

+0

请任何人帮忙... – hyd00

回答

0

我知道你正在Objective-c中编写一个应用程序,但这里是我写的代码,完全符合你在Swift中需要的,希望它能帮助你和任何寻找相同解决方案的人。

import Foundation 
import AVFoundation 
class AssetsLoader : NSObject { 
    public typealias AssetsLoaderCallback = ((IndexPath,AVPlayerItem)->Void) 
    private var callback: AssetsLoaderCallback 
    private(set) var loadedAssets: [IndexPath:AVURLAsset] = [:] 
    private(set) var pendingAssets: [IndexPath:AVURLAsset] = [:] 
    static var assetKeysRequiredToPlay = [ 
     "playable", 
     "tracks", 
     "duration" 
    ] 
    init(callback:@escaping AssetsLoaderCallback) { 
     self.callback = callback 
    } 

    func loadAssetsAsync(assets:[IndexPath:AVURLAsset]) { 
     loadedAssets = [:] 
     pendingAssets = [:] 
     for (key, value) in assets { 
      loadAssetAsync(index: key, asset: value) 
     } 
    } 

    private func loadAssetAsync(index:IndexPath,asset:AVURLAsset) { 
     asset.loadValuesAsynchronously(forKeys: AssetsLoader.assetKeysRequiredToPlay) { [weak self] in 
      for key in AssetsLoader.assetKeysRequiredToPlay { 
       var error : NSError? 
       if asset.statusOfValue(forKey: key, error: &error) == .failed { 
        //FIXME: Asset Could not load 
        print("Asset Could not load") 
       } 
      } 
      if !asset.isPlayable { 
       print("Cant play, move to next asset?") 
      } else { 
       // Asset Ready, Check if 
       self?.prepareAssetForCallback(index: index, asset: asset) 
      } 
     } 
    } 
    private func prepareAssetForCallback(index:IndexPath,asset:AVURLAsset) { 
     if index.row == 0 { 
      /// First Asset 
      loadedAssets[index] = asset 
      self.sendReadyAsset(index: index) 
      if let nextInline = pendingAssets[index.rowSuccessor()] { 
       self.freePendingAsset(index: index.rowSuccessor(), asset: nextInline) 
      } 
     } else { 
      self.freePendingAsset(index: index, asset: asset) 
     } 
    } 

    private func freePendingAsset(index:IndexPath,asset:AVURLAsset) { 
     if loadedAssets[index.rowPredecessor()] != nil && loadedAssets[index] == nil { 
      loadedAssets[index] = asset 
      self.sendReadyAsset(index: index) 
      if let nextInline = pendingAssets[index.rowSuccessor()] { 
       self.freePendingAsset(index: index.rowSuccessor(), asset: nextInline) 
      } 
     } else { 
      if pendingAssets[index] == nil { 
       pendingAssets[index] = asset 
      } 
     } 
    } 

    private func sendReadyAsset(index:IndexPath) { 
     self.callback(index, AVPlayerItem(asset:self.loadedAssets[index]!)) 
    } 
} 

NSIndexPath扩展:

extension IndexPath { 

    func rowPredecessor() -> IndexPath { 
     assert(self.row != 0, "-1 is an illegal index row") 
     return IndexPath(row: self.row - 1, section: self.section) 
    } 

    func rowSuccessor() -> IndexPath { 
     return IndexPath(row: self.row + 1, section: self.section) 
    } 
} 

只是一个回调初始化类,并通过调用该方法loadAssetAsyncNSIndexPathAVURLAsset要加载一些资产每次的字典。