Merge pull request #199 from sjchmiela/feature/additional_playback_callbacks
Additional playback callbacks
This commit is contained in:
commit
654ae1a27c
53
RCTVideo.m
53
RCTVideo.m
@ -7,6 +7,8 @@
|
|||||||
static NSString *const statusKeyPath = @"status";
|
static NSString *const statusKeyPath = @"status";
|
||||||
static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp";
|
static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp";
|
||||||
static NSString *const playbackBufferEmptyKeyPath = @"playbackBufferEmpty";
|
static NSString *const playbackBufferEmptyKeyPath = @"playbackBufferEmpty";
|
||||||
|
static NSString *const readyForDisplayKeyPath = @"readyForDisplay";
|
||||||
|
static NSString *const playbackRate = @"rate";
|
||||||
|
|
||||||
@implementation RCTVideo
|
@implementation RCTVideo
|
||||||
{
|
{
|
||||||
@ -36,6 +38,7 @@ static NSString *const playbackBufferEmptyKeyPath = @"playbackBufferEmpty";
|
|||||||
BOOL _muted;
|
BOOL _muted;
|
||||||
BOOL _paused;
|
BOOL _paused;
|
||||||
BOOL _repeat;
|
BOOL _repeat;
|
||||||
|
BOOL _playbackStalled;
|
||||||
NSString * _resizeMode;
|
NSString * _resizeMode;
|
||||||
BOOL _fullscreenPlayerPresented;
|
BOOL _fullscreenPlayerPresented;
|
||||||
UIViewController * _presentingViewController;
|
UIViewController * _presentingViewController;
|
||||||
@ -46,6 +49,7 @@ static NSString *const playbackBufferEmptyKeyPath = @"playbackBufferEmpty";
|
|||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
_eventDispatcher = eventDispatcher;
|
_eventDispatcher = eventDispatcher;
|
||||||
|
|
||||||
|
_playbackStalled = NO;
|
||||||
_rate = 1.0;
|
_rate = 1.0;
|
||||||
_volume = 1.0;
|
_volume = 1.0;
|
||||||
_resizeMode = @"AVLayerVideoGravityResizeAspectFill";
|
_resizeMode = @"AVLayerVideoGravityResizeAspectFill";
|
||||||
@ -213,13 +217,13 @@ static NSString *const playbackBufferEmptyKeyPath = @"playbackBufferEmpty";
|
|||||||
[self addPlayerItemObservers];
|
[self addPlayerItemObservers];
|
||||||
|
|
||||||
[_player pause];
|
[_player pause];
|
||||||
[_playerLayer removeFromSuperlayer];
|
[self removePlayerLayer];
|
||||||
_playerLayer = nil;
|
|
||||||
[_playerViewController.view removeFromSuperview];
|
[_playerViewController.view removeFromSuperview];
|
||||||
_playerViewController = nil;
|
_playerViewController = nil;
|
||||||
|
|
||||||
_player = [AVPlayer playerWithPlayerItem:_playerItem];
|
_player = [AVPlayer playerWithPlayerItem:_playerItem];
|
||||||
_player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
|
_player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
|
||||||
|
[_player addObserver:self forKeyPath:playbackRate options:0 context:nil];
|
||||||
|
|
||||||
const Float64 progressUpdateIntervalMS = _progressUpdateInterval / 1000;
|
const Float64 progressUpdateIntervalMS = _progressUpdateInterval / 1000;
|
||||||
// @see endScrubbing in AVPlayerDemoPlaybackViewController.m of https://developer.apple.com/library/ios/samplecode/AVPlayerDemo/Introduction/Intro.html
|
// @see endScrubbing in AVPlayerDemoPlaybackViewController.m of https://developer.apple.com/library/ios/samplecode/AVPlayerDemo/Introduction/Intro.html
|
||||||
@ -321,6 +325,25 @@ static NSString *const playbackBufferEmptyKeyPath = @"playbackBufferEmpty";
|
|||||||
}
|
}
|
||||||
_playerBufferEmpty = NO;
|
_playerBufferEmpty = NO;
|
||||||
}
|
}
|
||||||
|
} else if (object == _playerLayer) {
|
||||||
|
if([keyPath isEqualToString:readyForDisplayKeyPath] && [change objectForKey:NSKeyValueChangeNewKey]) {
|
||||||
|
if([change objectForKey:NSKeyValueChangeNewKey]) {
|
||||||
|
[_eventDispatcher sendInputEventWithName:@"onReadyForDisplay"
|
||||||
|
body:@{@"target": self.reactTag}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (object == _player) {
|
||||||
|
if([keyPath isEqualToString:playbackRate]) {
|
||||||
|
[_eventDispatcher sendInputEventWithName:@"onPlaybackRateChange"
|
||||||
|
body:@{@"playbackRate": [NSNumber numberWithFloat:_player.rate],
|
||||||
|
@"target": self.reactTag}];
|
||||||
|
if(_playbackStalled && _player.rate > 0) {
|
||||||
|
[_eventDispatcher sendInputEventWithName:@"onPlaybackResume"
|
||||||
|
body:@{@"playbackRate": [NSNumber numberWithFloat:_player.rate],
|
||||||
|
@"target": self.reactTag}];
|
||||||
|
_playbackStalled = NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
||||||
}
|
}
|
||||||
@ -333,6 +356,16 @@ static NSString *const playbackBufferEmptyKeyPath = @"playbackBufferEmpty";
|
|||||||
selector:@selector(playerItemDidReachEnd:)
|
selector:@selector(playerItemDidReachEnd:)
|
||||||
name:AVPlayerItemDidPlayToEndTimeNotification
|
name:AVPlayerItemDidPlayToEndTimeNotification
|
||||||
object:[_player currentItem]];
|
object:[_player currentItem]];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(playbackStalled:)
|
||||||
|
name:AVPlayerItemPlaybackStalledNotification
|
||||||
|
object:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)playbackStalled:(NSNotification *)notification
|
||||||
|
{
|
||||||
|
[_eventDispatcher sendInputEventWithName:@"onPlaybackStalled" body:@{@"target": self.reactTag}];
|
||||||
|
_playbackStalled = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)playerItemDidReachEnd:(NSNotification *)notification
|
- (void)playerItemDidReachEnd:(NSNotification *)notification
|
||||||
@ -518,6 +551,8 @@ static NSString *const playbackBufferEmptyKeyPath = @"playbackBufferEmpty";
|
|||||||
_playerLayer.frame = self.bounds;
|
_playerLayer.frame = self.bounds;
|
||||||
_playerLayer.needsDisplayOnBoundsChange = YES;
|
_playerLayer.needsDisplayOnBoundsChange = YES;
|
||||||
|
|
||||||
|
[_playerLayer addObserver:self forKeyPath:readyForDisplayKeyPath options:NSKeyValueObservingOptionNew context:nil];
|
||||||
|
|
||||||
[self.layer addSublayer:_playerLayer];
|
[self.layer addSublayer:_playerLayer];
|
||||||
self.layer.needsDisplayOnBoundsChange = YES;
|
self.layer.needsDisplayOnBoundsChange = YES;
|
||||||
}
|
}
|
||||||
@ -530,8 +565,7 @@ static NSString *const playbackBufferEmptyKeyPath = @"playbackBufferEmpty";
|
|||||||
_controls = controls;
|
_controls = controls;
|
||||||
if( _controls )
|
if( _controls )
|
||||||
{
|
{
|
||||||
[_playerLayer removeFromSuperlayer];
|
[self removePlayerLayer];
|
||||||
_playerLayer = nil;
|
|
||||||
[self usePlayerViewController];
|
[self usePlayerViewController];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -543,6 +577,13 @@ static NSString *const playbackBufferEmptyKeyPath = @"playbackBufferEmpty";
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)removePlayerLayer
|
||||||
|
{
|
||||||
|
[_playerLayer removeFromSuperlayer];
|
||||||
|
[_playerLayer removeObserver:self forKeyPath:readyForDisplayKeyPath];
|
||||||
|
_playerLayer = nil;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - RCTVideoPlayerViewControllerDelegate
|
#pragma mark - RCTVideoPlayerViewControllerDelegate
|
||||||
|
|
||||||
- (void)videoPlayerViewControllerWillDismiss:(AVPlayerViewController *)playerViewController
|
- (void)videoPlayerViewControllerWillDismiss:(AVPlayerViewController *)playerViewController
|
||||||
@ -626,10 +667,10 @@ static NSString *const playbackBufferEmptyKeyPath = @"playbackBufferEmpty";
|
|||||||
- (void)removeFromSuperview
|
- (void)removeFromSuperview
|
||||||
{
|
{
|
||||||
[_player pause];
|
[_player pause];
|
||||||
|
[_player removeObserver:self forKeyPath:playbackRate];
|
||||||
_player = nil;
|
_player = nil;
|
||||||
|
|
||||||
[_playerLayer removeFromSuperlayer];
|
[self removePlayerLayer];
|
||||||
_playerLayer = nil;
|
|
||||||
|
|
||||||
[_playerViewController.view removeFromSuperview];
|
[_playerViewController.view removeFromSuperview];
|
||||||
_playerViewController = nil;
|
_playerViewController = nil;
|
||||||
|
@ -28,7 +28,11 @@ RCT_EXPORT_MODULE();
|
|||||||
@"onVideoFullscreenPlayerWillPresent",
|
@"onVideoFullscreenPlayerWillPresent",
|
||||||
@"onVideoFullscreenPlayerDidPresent",
|
@"onVideoFullscreenPlayerDidPresent",
|
||||||
@"onVideoFullscreenPlayerWillDismiss",
|
@"onVideoFullscreenPlayerWillDismiss",
|
||||||
@"onVideoFullscreenPlayerDidDismiss"
|
@"onVideoFullscreenPlayerDidDismiss",
|
||||||
|
@"onReadyForDisplay",
|
||||||
|
@"onPlaybackStalled",
|
||||||
|
@"onPlaybackResume",
|
||||||
|
@"onPlaybackRateChange"
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
36
Video.js
36
Video.js
@ -38,6 +38,10 @@ export default class Video extends Component {
|
|||||||
this._onFullscreenPlayerDidPresent = this._onFullscreenPlayerDidPresent.bind(this);
|
this._onFullscreenPlayerDidPresent = this._onFullscreenPlayerDidPresent.bind(this);
|
||||||
this._onFullscreenPlayerWillDismiss = this._onFullscreenPlayerWillDismiss.bind(this);
|
this._onFullscreenPlayerWillDismiss = this._onFullscreenPlayerWillDismiss.bind(this);
|
||||||
this._onFullscreenPlayerDidDismiss = this._onFullscreenPlayerDidDismiss.bind(this);
|
this._onFullscreenPlayerDidDismiss = this._onFullscreenPlayerDidDismiss.bind(this);
|
||||||
|
this._onReadyForDisplay = this._onReadyForDisplay.bind(this);
|
||||||
|
this._onPlaybackStalled = this._onPlaybackStalled.bind(this);
|
||||||
|
this._onPlaybackResume = this._onPlaybackResume.bind(this);
|
||||||
|
this._onPlaybackRateChange = this._onPlaybackRateChange.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
setNativeProps(nativeProps) {
|
setNativeProps(nativeProps) {
|
||||||
@ -120,6 +124,30 @@ export default class Video extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onReadyForDisplay(event) {
|
||||||
|
if (this.props.onReadyForDisplay) {
|
||||||
|
this.props.onReadyForDisplay(event.nativeEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onPlaybackStalled(event) {
|
||||||
|
if (this.props.onPlaybackStalled) {
|
||||||
|
this.props.onPlaybackStalled(event.nativeEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onPlaybackResume(event) {
|
||||||
|
if (this.props.onPlaybackResume) {
|
||||||
|
this.props.onPlaybackResume(event.nativeEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onPlaybackRateChange(event) {
|
||||||
|
if (this.props.onPlaybackRateChange) {
|
||||||
|
this.props.onPlaybackRateChange(event.nativeEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
source,
|
source,
|
||||||
@ -165,6 +193,10 @@ export default class Video extends Component {
|
|||||||
onVideoFullscreenPlayerDidPresent: this._onFullscreenPlayerDidPresent,
|
onVideoFullscreenPlayerDidPresent: this._onFullscreenPlayerDidPresent,
|
||||||
onVideoFullscreenPlayerWillDismiss: this._onFullscreenPlayerWillDismiss,
|
onVideoFullscreenPlayerWillDismiss: this._onFullscreenPlayerWillDismiss,
|
||||||
onVideoFullscreenPlayerDidDismiss: this._onFullscreenPlayerDidDismiss,
|
onVideoFullscreenPlayerDidDismiss: this._onFullscreenPlayerDidDismiss,
|
||||||
|
onReadyForDisplay: this._onReadyForDisplay,
|
||||||
|
onPlaybackStalled: this._onPlaybackStalled,
|
||||||
|
onPlaybackResume: this._onPlaybackResume,
|
||||||
|
onPlaybackRateChange: this._onPlaybackRateChange,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -202,6 +234,10 @@ Video.propTypes = {
|
|||||||
onFullscreenPlayerDidPresent: PropTypes.func,
|
onFullscreenPlayerDidPresent: PropTypes.func,
|
||||||
onFullscreenPlayerWillDismiss: PropTypes.func,
|
onFullscreenPlayerWillDismiss: PropTypes.func,
|
||||||
onFullscreenPlayerDidDismiss: PropTypes.func,
|
onFullscreenPlayerDidDismiss: PropTypes.func,
|
||||||
|
onReadyForDisplay: PropTypes.func,
|
||||||
|
onPlaybackStalled: PropTypes.func,
|
||||||
|
onPlaybackResume: PropTypes.func,
|
||||||
|
onPlaybackRateChange: PropTypes.func,
|
||||||
|
|
||||||
/* Required by react-native */
|
/* Required by react-native */
|
||||||
scaleX: React.PropTypes.number,
|
scaleX: React.PropTypes.number,
|
||||||
|
Loading…
Reference in New Issue
Block a user