2016-06-12 28 views
0

Ich muss einige Audios hintereinander spielen, und daher AVQueuePlayer für diesen Zweck verwenden. Ich lade Audios in ihm als:Laden AVURLAsset asynchron in AVQueuePlayer stört die Reihenfolge - 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]; 

Das Problem ist jetzt, dass ich da bin, das Vermögen von URL über Async Laden (else Bedingung im Code siehe oben), die Reihenfolge der Audio-Dateien in meinem AVQueuePlayer ist wie die URLs in dem _messagesArray

zB nicht gleich: _messagesArray = audioURL1 , audioURL2, audioURL3

dann aufgrund async, je nachdem, was zuerst geladen, geht in AVQueuePlayer ersten

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

Bitte schlagen Sie eine Lösung vor, um die Bestellung in meinem Player zu erhalten.

Danke.

+0

Wenn Sie einfügen, können Sie anhand der Element-URL überprüfen, wo es nach _messageArray ist? – Larme

+0

@Larme können Sie bitte ein wenig ausarbeiten? habe nicht verstanden – hyd00

+0

Bitte jemand helfen ... – hyd00

Antwort

0

Ich weiß, dass Sie eine App in Objective-c schreiben, aber hier ist ein Code, den ich schrieb genau das, was Sie in Swift brauchen, hoffe, es hilft Ihnen und jedem auf der Suche nach der gleichen Lösung.

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 Erweiterung:

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

einfach die Klasse mit einem Rückruf initialisieren, und übergeben Sie rufen Sie die Methode loadAssetAsync mit einem Wörterbuch eines NSIndexPath und AVURLAsset jedes Mal, wenn Sie einige Vermögenswerte laden möchten.