Merge pull request #1076 from react-native-community/feature/ios-configurable-seek
Ability to specify seek tolerance on iOS
This commit is contained in:
		
							
								
								
									
										44
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								README.md
									
									
									
									
									
								
							@@ -240,6 +240,11 @@ var styles = StyleSheet.create({
 | 
				
			|||||||
* [onLoad](#onload)
 | 
					* [onLoad](#onload)
 | 
				
			||||||
* [onLoadStart](#onloadstart)
 | 
					* [onLoadStart](#onloadstart)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Methods
 | 
				
			||||||
 | 
					* [seek](#seek)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Configurable props
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### allowsExternalPlayback
 | 
					#### allowsExternalPlayback
 | 
				
			||||||
Indicates whether the player allows switching to external playback mode such as AirPlay or HDMI.
 | 
					Indicates whether the player allows switching to external playback mode such as AirPlay or HDMI.
 | 
				
			||||||
* **true (default)** - allow switching to external playback mode
 | 
					* **true (default)** - allow switching to external playback mode
 | 
				
			||||||
@@ -502,6 +507,45 @@ Example:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Platforms: all
 | 
					Platforms: all
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Methods
 | 
				
			||||||
 | 
					Methods operate on a ref to the Video element. You can create a ref using code like:
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					return (
 | 
				
			||||||
 | 
					  <Video source={...}
 | 
				
			||||||
 | 
					    ref => (this.player = ref) />
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### seek()
 | 
				
			||||||
 | 
					`seek(seconds)`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Seek to the specified position represented by seconds. seconds is a float value.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`seek()` can only be called after the `onLoad` event has fired.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Example:
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					this.player.seek(200); // Seek to 3 minutes, 20 seconds
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Platforms: all
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### Exact seek
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					By default iOS seeks within 100 milliseconds of the target position. If you need more accuracy, you can use the seek with tolerance method:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`seek(seconds, tolerance)`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tolerance is the max distance in milliseconds from the seconds position that's allowed. Using a more exact tolerance can cause seeks to take longer. If you want to seek exactly, set tolerance to 0.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Example:
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					this.player.seek(120, 50); // Seek to 2 minutes with +/- 50 milliseconds accuracy
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Platforms: iOS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Additional props
 | 
					### Additional props
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To see the full list of available props, you can check the [propTypes](https://github.com/react-native-community/react-native-video/blob/master/Video.js#L246) of the Video.js component.
 | 
					To see the full list of available props, you can check the [propTypes](https://github.com/react-native-community/react-native-video/blob/master/Video.js#L246) of the Video.js component.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										18
									
								
								Video.js
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								Video.js
									
									
									
									
									
								
							@@ -1,6 +1,6 @@
 | 
				
			|||||||
import React, {Component} from 'react';
 | 
					import React, {Component} from 'react';
 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
import {StyleSheet, requireNativeComponent, NativeModules, View, ViewPropTypes, Image} from 'react-native';
 | 
					import {StyleSheet, requireNativeComponent, NativeModules, View, ViewPropTypes, Image, Platform} from 'react-native';
 | 
				
			||||||
import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource';
 | 
					import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource';
 | 
				
			||||||
import TextTrackType from './TextTrackType';
 | 
					import TextTrackType from './TextTrackType';
 | 
				
			||||||
import VideoResizeMode from './VideoResizeMode.js';
 | 
					import VideoResizeMode from './VideoResizeMode.js';
 | 
				
			||||||
@@ -27,8 +27,17 @@ export default class Video extends Component {
 | 
				
			|||||||
    this._root.setNativeProps(nativeProps);
 | 
					    this._root.setNativeProps(nativeProps);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  seek = (time) => {
 | 
					  seek = (time, tolerance = 100) => {
 | 
				
			||||||
 | 
					    if (Platform.OS === 'ios') {
 | 
				
			||||||
 | 
					      this.setNativeProps({
 | 
				
			||||||
 | 
					        seek: {
 | 
				
			||||||
 | 
					          time,
 | 
				
			||||||
 | 
					          tolerance
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
      this.setNativeProps({ seek: time });
 | 
					      this.setNativeProps({ seek: time });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  presentFullscreenPlayer = () => {
 | 
					  presentFullscreenPlayer = () => {
 | 
				
			||||||
@@ -250,7 +259,10 @@ export default class Video extends Component {
 | 
				
			|||||||
Video.propTypes = {
 | 
					Video.propTypes = {
 | 
				
			||||||
  /* Native only */
 | 
					  /* Native only */
 | 
				
			||||||
  src: PropTypes.object,
 | 
					  src: PropTypes.object,
 | 
				
			||||||
  seek: PropTypes.number,
 | 
					  seek: PropTypes.oneOfType([
 | 
				
			||||||
 | 
					    PropTypes.number,
 | 
				
			||||||
 | 
					    PropTypes.object
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
  fullscreen: PropTypes.bool,
 | 
					  fullscreen: PropTypes.bool,
 | 
				
			||||||
  onVideoLoadStart: PropTypes.func,
 | 
					  onVideoLoadStart: PropTypes.func,
 | 
				
			||||||
  onVideoLoad: PropTypes.func,
 | 
					  onVideoLoad: PropTypes.func,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -569,21 +569,28 @@ static NSString *const timedMetadata = @"timedMetadata";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
- (void)setCurrentTime:(float)currentTime
 | 
					- (void)setCurrentTime:(float)currentTime
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  [self setSeek: currentTime];
 | 
					  NSDictionary *info = @{
 | 
				
			||||||
 | 
					                         @"time": [NSNumber numberWithFloat:currentTime],
 | 
				
			||||||
 | 
					                         @"tolerance": [NSNumber numberWithInt:100]
 | 
				
			||||||
 | 
					                         };
 | 
				
			||||||
 | 
					  [self setSeek:info];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- (void)setSeek:(float)seekTime
 | 
					- (void)setSeek:(NSDictionary *)info
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  int timeScale = 10000;
 | 
					  NSNumber *seekTime = info[@"time"];
 | 
				
			||||||
 | 
					  NSNumber *seekTolerance = info[@"tolerance"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int timeScale = 1000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  AVPlayerItem *item = _player.currentItem;
 | 
					  AVPlayerItem *item = _player.currentItem;
 | 
				
			||||||
  if (item && item.status == AVPlayerItemStatusReadyToPlay) {
 | 
					  if (item && item.status == AVPlayerItemStatusReadyToPlay) {
 | 
				
			||||||
    // TODO check loadedTimeRanges
 | 
					    // TODO check loadedTimeRanges
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CMTime cmSeekTime = CMTimeMakeWithSeconds(seekTime, timeScale);
 | 
					    CMTime cmSeekTime = CMTimeMakeWithSeconds([seekTime floatValue], timeScale);
 | 
				
			||||||
    CMTime current = item.currentTime;
 | 
					    CMTime current = item.currentTime;
 | 
				
			||||||
    // TODO figure out a good tolerance level
 | 
					    // TODO figure out a good tolerance level
 | 
				
			||||||
    CMTime tolerance = CMTimeMake(1000, timeScale);
 | 
					    CMTime tolerance = CMTimeMake([seekTolerance floatValue], timeScale);
 | 
				
			||||||
    BOOL wasPaused = _paused;
 | 
					    BOOL wasPaused = _paused;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (CMTimeCompare(current, cmSeekTime) != 0) {
 | 
					    if (CMTimeCompare(current, cmSeekTime) != 0) {
 | 
				
			||||||
@@ -597,7 +604,7 @@ static NSString *const timedMetadata = @"timedMetadata";
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        if(self.onVideoSeek) {
 | 
					        if(self.onVideoSeek) {
 | 
				
			||||||
            self.onVideoSeek(@{@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(item.currentTime)],
 | 
					            self.onVideoSeek(@{@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(item.currentTime)],
 | 
				
			||||||
                               @"seekTime": [NSNumber numberWithFloat:seekTime],
 | 
					                               @"seekTime": seekTime,
 | 
				
			||||||
                               @"target": self.reactTag});
 | 
					                               @"target": self.reactTag});
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }];
 | 
					      }];
 | 
				
			||||||
@@ -608,7 +615,7 @@ static NSString *const timedMetadata = @"timedMetadata";
 | 
				
			|||||||
  } else {
 | 
					  } 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;
 | 
					    _pendingSeek = true;
 | 
				
			||||||
    _pendingSeekTime = seekTime;
 | 
					    _pendingSeekTime = [seekTime floatValue];
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,7 +32,7 @@ RCT_EXPORT_VIEW_PROPERTY(playInBackground, BOOL);
 | 
				
			|||||||
RCT_EXPORT_VIEW_PROPERTY(playWhenInactive, BOOL);
 | 
					RCT_EXPORT_VIEW_PROPERTY(playWhenInactive, BOOL);
 | 
				
			||||||
RCT_EXPORT_VIEW_PROPERTY(ignoreSilentSwitch, NSString);
 | 
					RCT_EXPORT_VIEW_PROPERTY(ignoreSilentSwitch, NSString);
 | 
				
			||||||
RCT_EXPORT_VIEW_PROPERTY(rate, float);
 | 
					RCT_EXPORT_VIEW_PROPERTY(rate, float);
 | 
				
			||||||
RCT_EXPORT_VIEW_PROPERTY(seek, float);
 | 
					RCT_EXPORT_VIEW_PROPERTY(seek, NSDictionary);
 | 
				
			||||||
RCT_EXPORT_VIEW_PROPERTY(currentTime, float);
 | 
					RCT_EXPORT_VIEW_PROPERTY(currentTime, float);
 | 
				
			||||||
RCT_EXPORT_VIEW_PROPERTY(fullscreen, BOOL);
 | 
					RCT_EXPORT_VIEW_PROPERTY(fullscreen, BOOL);
 | 
				
			||||||
RCT_EXPORT_VIEW_PROPERTY(progressUpdateInterval, float);
 | 
					RCT_EXPORT_VIEW_PROPERTY(progressUpdateInterval, float);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user