@@ -337,13 +337,24 @@ - (void)observeValueForKeyPath:(NSString *)path
337
337
}
338
338
}
339
339
} else if (context == playbackBufferEmptyContext) {
340
- // There's a bug in AVFoundation, KVO for `playbackBufferEmpty` when playing HLS content. The
341
- // expected behavior of the value change for `playbackBufferEmpty` is not triggered. This
342
- // issue has been confirmed in iOS 16.5. Refer:
343
- // https://github.com/flutter/packages/pull/3826#discussion_r1204985454 Fortunately, the KVO
344
- // for `playbackBufferFull` is working correctly, so the bug won't affect the event passing
345
- // responsible for `bufferingEnd` or `bufferingStart` events.
346
340
if (_eventSink != nil ) {
341
+ // There's a bug in AVFoundation, KVO for `playbackBufferEmpty` when playing HLS content. The
342
+ // expected behavior of the value change for `playbackBufferEmpty` is not triggered. This
343
+ // issue has been confirmed in iOS 16.5. Refer:
344
+ // https://github.com/flutter/packages/pull/3826#discussion_r1204985454 Fortunately, the KVO
345
+ // for `playbackBufferFull` is working correctly, so the bug won't affect the event passing
346
+ // responsible for `bufferingEnd` or `bufferingStart` events.
347
+
348
+ // Here we check `isPlaybackLikelyToKeepUp` instead of `isPlaybackBufferEmpty` to determine if
349
+ // the playback is stalled or not. According to the Apple documentation for
350
+ // [`AVPlayerItem`](https://developer.apple.com/documentation/avfoundation/avplayeritem/1390348-playbacklikelytokeepup?language=objc),
351
+ // `isPlaybackLikelyToKeepUp` effectively indicates the likelihood of uninterrupted playback.
352
+ // When `isPlaybackBufferEmpty` is true, it indicates a possible stall or end of playback, as
353
+ // explained in the
354
+ // [documentation](https://developer.apple.com/documentation/avfoundation/avplayeritem/1386960-playbackbufferempty?language=objc).
355
+ // However, when `isPlaybackBufferEmpty` is false, we cannot determine if the playback is
356
+ // actively playing, stalled, or reaching the end. Therefore, we rely on
357
+ // `isPlaybackLikelyToKeepUp` to make this determination.
347
358
if ([[_player currentItem ] isPlaybackLikelyToKeepUp ]) {
348
359
_eventSink (@{@" event" : @" bufferingEnd" });
349
360
} else {
@@ -352,6 +363,17 @@ - (void)observeValueForKeyPath:(NSString *)path
352
363
}
353
364
} else if (context == playbackBufferFullContext) {
354
365
if (_eventSink != nil ) {
366
+ // Here we check `isPlaybackLikelyToKeepUp` instead of `isPlaybackBufferFull` to determine if
367
+ // the playback is stalled or not. The
368
+ // [`isPlaybackLikelyToKeepUp`](https://developer.apple.com/documentation/avfoundation/avplayeritem/1390348-playbacklikelytokeepup?language=objc)
369
+ // property effectively indicates the likelihood of uninterrupted playback. It's important to
370
+ // note that
371
+ // [`isPlaybackBufferFull`](https://developer.apple.com/documentation/avfoundation/avplayeritem/1388852-playbackbufferfull?language=objc)
372
+ // is not suitable for predicting playback stalling. Its purpose is to determine whether the
373
+ // internal media buffer is full and if further I/O is suspended, rather than indicating the
374
+ // playback status. Since `isPlaybackBufferFull` does not provide information about playback
375
+ // stall or end, we rely on `isPlaybackLikelyToKeepUp` to make a more accurate determination
376
+ // about the playback status.
355
377
if ([[_player currentItem ] isPlaybackLikelyToKeepUp ]) {
356
378
_eventSink (@{@" event" : @" bufferingEnd" });
357
379
} else {
0 commit comments