Commit 28d48285 authored by Baris Sencan's avatar Baris Sencan
Browse files

Act according to playbackLikelyToKeepUp changes

Closes #57
This commit also includes some code style updates
parent db402be6
Loading
Loading
Loading
Loading
+44 −42
Changes for RCTVideo.m: 44 added lines, 42 removed lines.
Original line number Diff line number Diff line
@@ -13,12 +13,13 @@ NSString *const RNVideoEventLoadingError = @"videoLoadError";
NSString *const RNVideoEventEnd = @"videoEnd";

static NSString *const statusKeyPath = @"status";
static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp";

@implementation RCTVideo
{
  AVPlayer *_player;
  AVPlayerItem *_playerItem;
  BOOL _playerItemObserverSet;
  BOOL _playerItemObserversSet;
  AVPlayerLayer *_playerLayer;
  NSURL *_videoURL;

@@ -99,14 +100,11 @@ static NSString *const statusKeyPath = @"status";
    return;
  }

  if (_prevProgressUpdateTime == nil ||
     (([_prevProgressUpdateTime timeIntervalSinceNow] * -1000.0) >= _progressUpdateInterval)) {
    [_eventDispatcher sendInputEventWithName:RNVideoEventProgress body:@{
      @"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(video.currentTime)],
  if (_prevProgressUpdateTime == nil || (([_prevProgressUpdateTime timeIntervalSinceNow] * -1000.0) >= _progressUpdateInterval)) {
    [_eventDispatcher sendInputEventWithName:RNVideoEventProgress
                                        body:@{@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(video.currentTime)],
                                               @"playableDuration": [self calculatePlayableDuration],
      @"target": self.reactTag
    }];

                                               @"target": self.reactTag}];
    _prevProgressUpdateTime = [NSDate date];
  }
}
@@ -116,7 +114,8 @@ static NSString *const statusKeyPath = @"status";
 *
 * \returns The playable duration of the current player item in seconds.
 */
- (NSNumber *)calculatePlayableDuration {
- (NSNumber *)calculatePlayableDuration
{
  AVPlayerItem *video = _player.currentItem;
  if (video.status == AVPlayerItemStatusReadyToPlay) {
    __block CMTimeRange effectiveTimeRange;
@@ -151,20 +150,22 @@ static NSString *const statusKeyPath = @"status";
  [_progressUpdateTimer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
}

- (void)addPlayerItemObserver
- (void)addPlayerItemObservers
{
  [_playerItem addObserver:self forKeyPath:statusKeyPath options:0 context:nil];
  _playerItemObserverSet = YES;
  [_playerItem addObserver:self forKeyPath:playbackLikelyToKeepUpKeyPath options:0 context:nil];
  _playerItemObserversSet = YES;
}

/* Fixes https://github.com/brentvatne/react-native-video/issues/43
 * Crashes caused when trying to remove the observer when there is no
 * observer set */
- (void)removePlayerItemObserver
- (void)removePlayerItemObservers
{
  if (_playerItemObserverSet) {
  if (_playerItemObserversSet) {
    [_playerItem removeObserver:self forKeyPath:statusKeyPath];
    _playerItemObserverSet = NO;
    [_playerItem removeObserver:self forKeyPath:playbackLikelyToKeepUpKeyPath];
    _playerItemObserversSet = NO;
  }
}

@@ -172,9 +173,9 @@ static NSString *const statusKeyPath = @"status";

- (void)setSrc:(NSDictionary *)source
{
  [self removePlayerItemObserver];
  [self removePlayerItemObservers];
  _playerItem = [self playerItemForSource:source];
  [self addPlayerItemObserver];
  [self addPlayerItemObservers];

  [_player pause];
  [_playerLayer removeFromSuperlayer];
@@ -191,14 +192,12 @@ static NSString *const statusKeyPath = @"status";
  [self.layer addSublayer:_playerLayer];
  self.layer.needsDisplayOnBoundsChange = YES;

  [_eventDispatcher sendInputEventWithName:RNVideoEventLoading body:@{
    @"src": @{
  [_eventDispatcher sendInputEventWithName:RNVideoEventLoading
                                      body:@{@"src": @{
                                                 @"uri": [source objectForKey:@"uri"],
                                                 @"type": [source objectForKey:@"type"],
      @"isNetwork":[NSNumber numberWithBool:(bool)[source objectForKey:@"isNetwork"]]
    },
    @"target": self.reactTag
  }];
                                                 @"isNetwork":[NSNumber numberWithBool:(bool)[source objectForKey:@"isNetwork"]]},
                                             @"target": self.reactTag}];
}

- (AVPlayerItem*)playerItemForSource:(NSDictionary *)source
@@ -223,6 +222,9 @@ static NSString *const statusKeyPath = @"status";
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
  if (object == _playerItem) {

    if ([keyPath isEqualToString:statusKeyPath]) {
      // Handle player item status change.
      if (_playerItem.status == AVPlayerItemStatusReadyToPlay) {
        float duration = CMTimeGetSeconds(_playerItem.asset.duration);

@@ -230,8 +232,8 @@ static NSString *const statusKeyPath = @"status";
          duration = 0.0;
        }

      [_eventDispatcher sendInputEventWithName:RNVideoEventLoaded body:@{
        @"duration": [NSNumber numberWithFloat:duration],
        [_eventDispatcher sendInputEventWithName:RNVideoEventLoaded
                                            body:@{@"duration": [NSNumber numberWithFloat:duration],
                                                   @"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(_playerItem.currentTime)],
                                                   @"canPlayReverse": [NSNumber numberWithBool:_playerItem.canPlayReverse],
                                                   @"canPlayFastForward": [NSNumber numberWithBool:_playerItem.canPlayFastForward],
@@ -239,20 +241,23 @@ static NSString *const statusKeyPath = @"status";
                                                   @"canPlaySlowReverse": [NSNumber numberWithBool:_playerItem.canPlaySlowReverse],
                                                   @"canStepBackward": [NSNumber numberWithBool:_playerItem.canStepBackward],
                                                   @"canStepForward": [NSNumber numberWithBool:_playerItem.canStepForward],
        @"target": self.reactTag
      }];
                                                   @"target": self.reactTag}];

        [self startProgressTimer];
        [self attachListeners];
        [self applyModifiers];
      } else if(_playerItem.status == AVPlayerItemStatusFailed) {
      [_eventDispatcher sendInputEventWithName:RNVideoEventLoadingError body:@{
        @"error": @{
        [_eventDispatcher sendInputEventWithName:RNVideoEventLoadingError
                                            body:@{@"error": @{
                                                       @"code": [NSNumber numberWithInteger: _playerItem.error.code],
          @"domain": _playerItem.error.domain
        },
        @"target": self.reactTag
      }];
                                                       @"domain": _playerItem.error.domain},
                                                   @"target": self.reactTag}];
      }
    } else if ([keyPath isEqualToString:playbackLikelyToKeepUpKeyPath]) {
      // Continue playing (or not if paused) after being paused due to hitting an unbuffered zone.
      if (_playerItem.playbackLikelyToKeepUp) {
        [self setPaused:_paused];
      }
    }
  } else {
    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
@@ -270,9 +275,8 @@ static NSString *const statusKeyPath = @"status";

- (void)playerItemDidReachEnd:(NSNotification *)notification
{
  [_eventDispatcher sendInputEventWithName:RNVideoEventEnd body:@{
    @"target": self.reactTag
  }];
  [_eventDispatcher sendInputEventWithName:RNVideoEventEnd body:@{@"target": self.reactTag}];

  if (_repeat) {
    AVPlayerItem *item = [notification object];
    [item seekToTime:kCMTimeZero];
@@ -316,19 +320,17 @@ static NSString *const statusKeyPath = @"status";

    if (CMTimeCompare(current, cmSeekTime) != 0) {
      [_player seekToTime:cmSeekTime toleranceBefore:tolerance toleranceAfter:tolerance completionHandler:^(BOOL finished) {
        [_eventDispatcher sendInputEventWithName:RNVideoEventSeek body:@{
          @"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(item.currentTime)],
        [_eventDispatcher sendInputEventWithName:RNVideoEventSeek
                                            body:@{@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(item.currentTime)],
                                                   @"seekTime": [NSNumber numberWithFloat:seekTime],
          @"target": self.reactTag
        }];
                                                   @"target": self.reactTag}];
      }];

      _pendingSeek = false;
    }

  } else {
    // TODO see if this makes sense and if so,
    // actually implement it
    // TODO: See if this makes sense and if so, actually implement it
    _pendingSeek = true;
    _pendingSeekTime = seekTime;
  }
@@ -407,7 +409,7 @@ static NSString *const statusKeyPath = @"status";
  [_playerLayer removeFromSuperlayer];
  _playerLayer = nil;

  [self removePlayerItemObserver];
  [self removePlayerItemObservers];

  _eventDispatcher = nil;
  [[NSNotificationCenter defaultCenter] removeObserver:self];