Skip to content

Commit

Permalink
Merge pull request #1076 from react-native-community/feature/ios-conf…
Browse files Browse the repository at this point in the history
…igurable-seek

Ability to specify seek tolerance on iOS
  • Loading branch information
cobarx authored Jun 21, 2018
2 parents dc4c180 + 9401328 commit 0418d8a
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 13 deletions.
44 changes: 44 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,11 @@ var styles = StyleSheet.create({
* [onLoad](#onload)
* [onLoadStart](#onloadstart)

### Methods
* [seek](#seek)

### Configurable props

#### allowsExternalPlayback
Indicates whether the player allows switching to external playback mode such as AirPlay or HDMI.
* **true (default)** - allow switching to external playback mode
Expand Down Expand Up @@ -502,6 +507,45 @@ Example:

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

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.
Expand Down
20 changes: 16 additions & 4 deletions Video.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, {Component} from 'react';
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 TextTrackType from './TextTrackType';
import VideoResizeMode from './VideoResizeMode.js';
Expand All @@ -27,8 +27,17 @@ export default class Video extends Component {
this._root.setNativeProps(nativeProps);
}

seek = (time) => {
this.setNativeProps({ seek: time });
seek = (time, tolerance = 100) => {
if (Platform.OS === 'ios') {
this.setNativeProps({
seek: {
time,
tolerance
}
});
} else {
this.setNativeProps({ seek: time });
}
};

presentFullscreenPlayer = () => {
Expand Down Expand Up @@ -250,7 +259,10 @@ export default class Video extends Component {
Video.propTypes = {
/* Native only */
src: PropTypes.object,
seek: PropTypes.number,
seek: PropTypes.oneOfType([
PropTypes.number,
PropTypes.object
]),
fullscreen: PropTypes.bool,
onVideoLoadStart: PropTypes.func,
onVideoLoad: PropTypes.func,
Expand Down
23 changes: 15 additions & 8 deletions ios/RCTVideo.m
Original file line number Diff line number Diff line change
Expand Up @@ -569,21 +569,28 @@ - (float)getCurrentTime

- (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;
if (item && item.status == AVPlayerItemStatusReadyToPlay) {
// TODO check loadedTimeRanges

CMTime cmSeekTime = CMTimeMakeWithSeconds(seekTime, timeScale);
CMTime cmSeekTime = CMTimeMakeWithSeconds([seekTime floatValue], timeScale);
CMTime current = item.currentTime;
// TODO figure out a good tolerance level
CMTime tolerance = CMTimeMake(1000, timeScale);
CMTime tolerance = CMTimeMake([seekTolerance floatValue], timeScale);
BOOL wasPaused = _paused;

if (CMTimeCompare(current, cmSeekTime) != 0) {
Expand All @@ -593,11 +600,11 @@ - (void)setSeek:(float)seekTime
[self addPlayerTimeObserver];
}
if (!wasPaused) {
[self setPaused:false];
[self setPaused:false];
}
if(self.onVideoSeek) {
self.onVideoSeek(@{@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(item.currentTime)],
@"seekTime": [NSNumber numberWithFloat:seekTime],
@"seekTime": seekTime,
@"target": self.reactTag});
}
}];
Expand All @@ -608,7 +615,7 @@ - (void)setSeek:(float)seekTime
} else {
// TODO: See if this makes sense and if so, actually implement it
_pendingSeek = true;
_pendingSeekTime = seekTime;
_pendingSeekTime = [seekTime floatValue];
}
}

Expand Down
2 changes: 1 addition & 1 deletion ios/RCTVideoManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ - (dispatch_queue_t)methodQueue
RCT_EXPORT_VIEW_PROPERTY(playWhenInactive, BOOL);
RCT_EXPORT_VIEW_PROPERTY(ignoreSilentSwitch, NSString);
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(fullscreen, BOOL);
RCT_EXPORT_VIEW_PROPERTY(progressUpdateInterval, float);
Expand Down

0 comments on commit 0418d8a

Please sign in to comment.