【问题标题】:How to do something when AVQueuePlayer finishes the last playeritem当 AVQueuePlayer 完成最后一个播放项时如何做某事
【发布时间】:2012-08-29 23:04:39
【问题描述】:

我有一个 AVQueuePlayer,它是从 4 个 AVPlayerItem 的数组中创建的,并且一切正常。

我想在队列中的最后一个项目播放完时做点什么,我在这里查看了很多答案,这是我想要的最有希望的答案: The best way to execute code AFTER a sound has finished playing

在我的按钮处理程序中,我有以下代码:

static const NSString *ItemStatusContext;

    [thePlayerItemA addObserver:self forKeyPath:@"status" options:0 context:&ItemStatusContext];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(playerItemDidReachEnd)
                                                 name:AVPlayerItemDidPlayToEndTimeNotification
                                               object:thePlayerItemA];

     theQueuePlayer = [AVQueuePlayer playerWithPlayerItem:thePlayerItemA]; 

    [theQueuePlayer play];

然后我有一个函数来处理 playerItemDidReachEnd:

- (void)playerItemDidReachEnd:(NSNotification *)notification {
// Do stuff here
NSLog(@"IT REACHED THE END");
}

但是当我运行这个时,我得到一个内部不一致异常:

    An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.
Key path: status
Observed object: <AVPlayerItem: 0x735a130, asset = <AVURLAsset: 0x73559c0, URL = file://localhost/Users/mike/Library/Application%20Support/iPhone%20Simulator/5.0/Applications/A0DBEC13-2DA6-4887-B29D-B43A78E173B8/Phonics%2001.app/yes.mp3>>
Change: {
    kind = 1;

}

我做错了什么?

【问题讨论】:

    标签: objective-c ios avqueueplayer


    【解决方案1】:

    这种方法似乎对我有用,在我的按钮处理程序中,我有很多东西可以为我想要播放的 4 个 mp3 文件创建 URL,然后:

    AVPlayerItem *thePlayerItemA = [[AVPlayerItem alloc] initWithURL:urlA];
    AVPlayerItem *thePlayerItemB = [[AVPlayerItem alloc] initWithURL:urlB];
    AVPlayerItem *thePlayerItemC = [[AVPlayerItem alloc] initWithURL:urlC];    
    AVPlayerItem *thePlayerItemD = [[AVPlayerItem alloc] initWithURL:urlD];  
    
    NSArray *theItems = [NSArray arrayWithObjects:thePlayerItemA, thePlayerItemB, thePlayerItemC, thePlayerItemD, nil];
    theQueuePlayer = [AVQueuePlayer queuePlayerWithItems:theItems];
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(playerItemDidReachEnd:)
                                                 name:AVPlayerItemDidPlayToEndTimeNotification
                                               object:[theItems lastObject]];
    [theQueuePlayer play];
    

    之后我实现了这样的“playerItemDidReachEnd”选择器:

    - (void)playerItemDidReachEnd:(NSNotification *)notification {
        // Do stuff here
        NSLog(@"IT REACHED THE END");
    }
    

    这会将 4 个 MP3 文件排队,然后当最后一段音频完成时,它会调用选择器,我的消息会出现在控制台中。

    我希望这对其他人有用。

    【讨论】:

      【解决方案2】:

      观察状态不会告诉你项目何时完成播放(它只告诉你项目何时准备播放)

      您所要做的就是注册AVPlayerItemDidPlayToEndTimeNotification 您的playbackQueue 中的lastItem,用于初始化您的AVQueuePlayer 实例。

      AVQueuePlayer* player = [AVQueuePlayer queuePlayerWithItems:currentPlaybackQueue];
      [[NSNotificationCenter defaultCenter] addObserver:self
                                                   selector:@selector(playerItemDidReachEnd:)
                                                       name:AVPlayerItemDidPlayToEndTimeNotification
                                                     object:currentPlaybackQueue.lastObject];
      

      (注意选择器有playerItemDidReachEnd:,你忘了两个点)

      那么-playerItemDidReachEnd: 最终只会在你需要的时候被调用一次。 (也不要忘记将自己移除为观察者 - 您可以在 -playerItemDidReachEnd: 中使用 notification.object 进行此操作)

      不得不说还有其他方法可以做到这一点: 对 currentItem 使用 key-value 观察,然后检查 observeValueForKeyPath: 中的 currentItem 是否更改为 [NSNull null]

      [player addObserver:self forKeyPath:@"currentItem" options:NSKeyValueObservingOptionNew context:nil];
      
      - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
      {
          if ([keyPath isEqualToString:@"currentItem"]) {
      
              if (change[NSKeyValueChangeNewKey] == [NSNull null]) {
                  //last item finished playing - do something
      
              }
          }
      }
      

      通常对于AVQueuePlayer,您将为playbackQueue 中的每个项目注册AVPlayerItemDidPlayToEndTimeNotification,所以除非您不想在本地存储playbackQueue 并在-playerItemDidReachEnd: 中使用notification.object 检查其lastObject,否则您会使用第二种方式

      【讨论】:

        【解决方案3】:

        您可能没有在您的课程中实现-observeValueForKeyPath:ofObject:change:context: 方法。查看Apple KVO guide了解更多详情。

        【讨论】:

        • 谢谢,我今晚试试。
        • 我使用 NSNotificationCenter 而不是 KVO 让它工作,似乎我盲目复制和粘贴的示例试图同时使用这两种方法。
        • 好的,是的,我想知道你为什么同时做这两个。希望这有帮助。赞成和/或接受将不胜感激:)
        猜你喜欢
        • 1970-01-01
        • 2021-02-13
        • 1970-01-01
        • 1970-01-01
        • 2020-10-27
        • 1970-01-01
        • 1970-01-01
        • 2012-06-24
        • 1970-01-01
        相关资源
        最近更新 更多