Skip to content

Commit 3994e73

Browse files
committed
Address some of the feedback from the pull reqeust
1 parent 78b8ca2 commit 3994e73

File tree

5 files changed

+61
-88
lines changed

5 files changed

+61
-88
lines changed

README.md

+21-48
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ var styles = StyleSheet.create({
266266
* [ignoreSilentSwitch](#ignoresilentswitch)
267267
* [muted](#muted)
268268
* [paused](#paused)
269+
* [pictureInPicture](#pictureinpicture)
269270
* [playInBackground](#playinbackground)
270271
* [playWhenInactive](#playwheninactive)
271272
* [poster](#poster)
@@ -283,15 +284,15 @@ var styles = StyleSheet.create({
283284
* [volume](#volume)
284285

285286
### Event props
287+
* [needsToRestoreUserInterfaceForPictureInPictureStop](#needstorestoreuserinterfaceforpictureinpicturestop)
286288
* [onAudioBecomingNoisy](#onaudiobecomingnoisy)
287289
* [onEnd](#onend)
288290
* [onExternalPlaybackChange](#onexternalplaybackchange)
289291
* [onFullscreenPlayerWillPresent](#onfullscreenplayerwillpresent)
290292
* [onFullscreenPlayerDidPresent](#onfullscreenplayerdidpresent)
291293
* [onFullscreenPlayerWillDismiss](#onfullscreenplayerwilldismiss)
292294
* [onFullscreenPlayerDidDismiss](#onfullscreenplayerdiddismiss)
293-
* [onIsPictureInPictureActive](#onispictureinpictureactive)
294-
* [onIsPictureInPictureSupported](#onispictureinpicturesupported)
295+
* [onPictureInPictureStatusChanged](#onpictureinpicturestatuschanged)
295296
* [onLoad](#onload)
296297
* [onLoadStart](#onloadstart)
297298
* [onProgress](#onprogress)
@@ -301,9 +302,7 @@ var styles = StyleSheet.create({
301302
* [dismissFullscreenPlayer](#dismissfullscreenplayer)
302303
* [presentFullscreenPlayer](#presentfullscreenplayer)
303304
* [restoreUserInterfaceForPictureInPictureStop](#restoreuserinterfaceforpictureinpicturestop)
304-
* [startPictureInPicture](#startpictureinpicture)
305305
* [seek](#seek)
306-
* [stopPictureInPicture](#stoppictureinpicture)
307306

308307
### Configurable props
309308

@@ -418,6 +417,13 @@ Controls whether the media is paused
418417

419418
Platforms: all
420419

420+
#### pictureInPicture
421+
Determine whether the media should played as picture in picture.
422+
* **false (default)** - Don't not play as picture in picture
423+
* **true** - Play the media as picture in picture
424+
425+
Platforms: iOS
426+
421427
#### playInBackground
422428
Determine whether the media should continue playing while the app is in the background. This allows customers to continue listening to the audio.
423429
* **false (default)** - Don't continue playing the media
@@ -672,6 +678,13 @@ Platforms: all
672678

673679
### Event props
674680

681+
#### needsToRestoreUserInterfaceForPictureInPictureStop
682+
Callback function that is called when picture in picture is stopped and requires restoring the user interface. Call `restoreUserInterfaceForPictureInPictureStop` when this method is called.
683+
684+
Payload: none
685+
686+
Platforms: iOS
687+
675688
#### onAudioBecomingNoisy
676689
Callback function that is called when the audio is about to become 'noisy' due to a change in audio outputs. Typically this is called when audio output is being switched from an external source like headphones back to the internal speaker. It's a good idea to pause the media when this happens so the speaker doesn't start blasting sound.
677690

@@ -732,33 +745,17 @@ Payload: none
732745

733746
Platforms: Android ExoPlayer, Android MediaPlayer, iOS
734747

735-
#### onIsPictureInPictureActive
748+
#### onPictureInPictureStatusChanged
736749
Callback function that is called when picture in picture becomes active or inactive.
737750

738751
Property | Type | Description
739752
--- | --- | ---
740-
active | boolean | Boolean indicating whether picture in picture is active
741-
742-
Example:
743-
```
744-
{
745-
active: true
746-
}
747-
```
748-
749-
Platforms: iOS
750-
751-
#### onIsPictureInPictureSupported
752-
Callback function that is called initially to determine whether or not picture in picture is supported.
753-
754-
Property | Type | Description
755-
--- | --- | ---
756-
supported | boolean | Boolean indicating whether picture in picture is supported
753+
isActive | boolean | Boolean indicating whether picture in picture is active
757754

758755
Example:
759756
```
760757
{
761-
supported: true
758+
isActive: true
762759
}
763760
```
764761

@@ -913,7 +910,7 @@ Platforms: Android ExoPlayer, Android MediaPlayer, iOS
913910
#### restoreUserInterfaceForPictureInPictureStop
914911
`restoreUserInterfaceForPictureInPictureStop(restore)`
915912

916-
This function corresponds to Apple's [restoreUserInterfaceForPictureInPictureStop](https://developer.apple.com/documentation/avkit/avpictureinpicturecontrollerdelegate/1614703-pictureinpicturecontroller?language=objc). IMPORTANT: After picture in picture stops, this function must be called.
913+
This function corresponds to Apple's [restoreUserInterfaceForPictureInPictureStop](https://developer.apple.com/documentation/avkit/avpictureinpicturecontrollerdelegate/1614703-pictureinpicturecontroller?language=objc). IMPORTANT: This function must be called after needsToRestoreUserInterfaceForPictureInPictureStop is called.
917914

918915
Example:
919916
```
@@ -922,18 +919,6 @@ this.player.restoreUserInterfaceForPictureInPictureStop(true);
922919

923920
Platforms: iOS
924921

925-
#### startPictureInPicture
926-
`startPictureInPicture()`
927-
928-
Calling this function will start picture in picture if it is supported.
929-
930-
Example:
931-
```
932-
this.player.startPictureInPicture();
933-
```
934-
935-
Platforms: iOS
936-
937922
#### seek()
938923
`seek(seconds)`
939924

@@ -963,18 +948,6 @@ this.player.seek(120, 50); // Seek to 2 minutes with +/- 50 milliseconds accurac
963948

964949
Platforms: iOS
965950

966-
#### stopPictureInPicture
967-
`stopPictureInPicture()`
968-
969-
Calling this function will stop picture in picture if it is currently active.
970-
971-
Example:
972-
```
973-
this.player.stopPictureInPicture();
974-
```
975-
976-
Platforms: iOS
977-
978951

979952
### iOS App Transport Security
980953

Video.js

+11-18
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,6 @@ export default class Video extends Component {
7171
this.setNativeProps({ fullscreen: false });
7272
};
7373

74-
startPictureInPicture = () => {
75-
this.setNativeProps({ pictureInPicture: true });
76-
};
77-
78-
stopPictureInPicture = () => {
79-
this.setNativeProps({ pictureInPicture: false });
80-
};
81-
8274
restoreUserInterfaceForPictureInPictureStop = (restore) => {
8375
this.setNativeProps({ restoreUserInterfaceForPIPStopCompletionHandler: restore });
8476
};
@@ -197,15 +189,15 @@ export default class Video extends Component {
197189
}
198190
};
199191

200-
_onIsPictureInPictureSupported = (event) => {
201-
if (this.props.onIsPictureInPictureSupported) {
202-
this.props.onIsPictureInPictureSupported(event.nativeEvent);
192+
_onPictureInPictureStatusChanged = (event) => {
193+
if (this.props.onPictureInPictureStatusChanged) {
194+
this.props.onPictureInPictureStatusChanged(event.nativeEvent);
203195
}
204196
};
205197

206-
_onIsPictureInPictureActive = (event) => {
207-
if (this.props.onIsPictureInPictureActive) {
208-
this.props.onIsPictureInPictureActive(event.nativeEvent);
198+
_needsToRestoreUserInterfaceForPictureInPictureStop = (event) => {
199+
if (this.props.needsToRestoreUserInterfaceForPictureInPictureStop) {
200+
this.props.needsToRestoreUserInterfaceForPictureInPictureStop();
209201
}
210202
};
211203

@@ -277,8 +269,8 @@ export default class Video extends Component {
277269
onPlaybackRateChange: this._onPlaybackRateChange,
278270
onAudioFocusChanged: this._onAudioFocusChanged,
279271
onAudioBecomingNoisy: this._onAudioBecomingNoisy,
280-
onIsPictureInPictureSupported: this._onIsPictureInPictureSupported,
281-
onIsPictureInPictureActive: this._onIsPictureInPictureActive,
272+
onPictureInPictureStatusChanged: this._onPictureInPictureStatusChanged,
273+
needsToRestoreUserInterfaceForPictureInPictureStop: this._needsToRestoreUserInterfaceForPictureInPictureStop,
282274
});
283275

284276
const posterStyle = {
@@ -373,6 +365,7 @@ Video.propTypes = {
373365
}),
374366
stereoPan: PropTypes.number,
375367
rate: PropTypes.number,
368+
pictureInPicture: PropTypes.bool,
376369
playInBackground: PropTypes.bool,
377370
playWhenInactive: PropTypes.bool,
378371
ignoreSilentSwitch: PropTypes.oneOf(['ignore', 'obey']),
@@ -400,8 +393,8 @@ Video.propTypes = {
400393
onPlaybackRateChange: PropTypes.func,
401394
onAudioFocusChanged: PropTypes.func,
402395
onAudioBecomingNoisy: PropTypes.func,
403-
onIsPictureInPictureSupported: PropTypes.func,
404-
onIsPictureInPictureActive: PropTypes.func,
396+
onPictureInPictureStatusChanged: PropTypes.func,
397+
needsToRestoreUserInterfaceForPictureInPictureStop: PropTypes.func,
405398
onExternalPlaybackChange: PropTypes.func,
406399

407400
/* Required by react-native */

ios/Video/RCTVideo.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@
3737
@property (nonatomic, copy) RCTBubblingEventBlock onPlaybackRateChange;
3838
@property (nonatomic, copy) RCTBubblingEventBlock onVideoExternalPlaybackChange;
3939
@property (nonatomic, copy) RCTBubblingEventBlock onIsPictureInPictureSupported;
40-
@property (nonatomic, copy) RCTBubblingEventBlock onIsPictureInPictureActive;
40+
@property (nonatomic, copy) RCTBubblingEventBlock onPictureInPictureStatusChanged;
41+
@property (nonatomic, copy) RCTBubblingEventBlock needsToRestoreUserInterfaceForPictureInPictureStop;
4142

4243
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
4344

ios/Video/RCTVideo.m

+24-18
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ @implementation RCTVideo
6363
BOOL _playbackStalled;
6464
BOOL _playInBackground;
6565
BOOL _playWhenInactive;
66+
BOOL _pictureInPicture;
6667
NSString * _ignoreSilentSwitch;
6768
NSString * _resizeMode;
6869
BOOL _fullscreen;
@@ -95,6 +96,7 @@ - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
9596
_playInBackground = false;
9697
_allowsExternalPlayback = YES;
9798
_playWhenInactive = false;
99+
_pictureInPicture = false;
98100
_ignoreSilentSwitch = @"inherit"; // inherit, ignore, obey
99101
_restoreUserInterfaceForPIPStopCompletionHandler = NULL;
100102
#if __has_include(<react-native-video/RCTVideoCache.h>)
@@ -372,12 +374,6 @@ - (void)setSrc:(NSDictionary *)source
372374
@"target": self.reactTag
373375
});
374376
}
375-
376-
if (@available(iOS 9, *)) {
377-
if (self.onIsPictureInPictureSupported) {
378-
self.onIsPictureInPictureSupported(@{@"supported": [NSNumber numberWithBool:(bool)[AVPictureInPictureController isPictureInPictureSupported]]});
379-
}
380-
}
381377
}];
382378
});
383379
_videoLoadStarted = YES;
@@ -758,11 +754,16 @@ - (void)setPlayWhenInactive:(BOOL)playWhenInactive
758754

759755
- (void)setPictureInPicture:(BOOL)pictureInPicture
760756
{
761-
if (_pipController && pictureInPicture && ![_pipController isPictureInPictureActive]) {
757+
if (_pictureInPicture == pictureInPicture) {
758+
return;
759+
}
760+
761+
_pictureInPicture = pictureInPicture;
762+
if (_pipController && _pictureInPicture && ![_pipController isPictureInPictureActive]) {
762763
dispatch_async(dispatch_get_main_queue(), ^{
763764
[_pipController startPictureInPicture];
764765
});
765-
} else if (_pipController && !pictureInPicture && [_pipController isPictureInPictureActive]) {
766+
} else if (_pipController && !_pictureInPicture && [_pipController isPictureInPictureActive]) {
766767
dispatch_async(dispatch_get_main_queue(), ^{
767768
[_pipController stopPictureInPicture];
768769
});
@@ -778,12 +779,10 @@ - (void)setRestoreUserInterfaceForPIPStopCompletionHandler:(BOOL)restore
778779
}
779780

780781
- (void)setupPipController {
781-
if (@available(iOS 9, *)) {
782-
if (!_pipController && _playerLayer && [AVPictureInPictureController isPictureInPictureSupported]) {
783-
// Create new controller passing reference to the AVPlayerLayer
784-
_pipController = [[AVPictureInPictureController alloc] initWithPlayerLayer:_playerLayer];
785-
_pipController.delegate = self;
786-
}
782+
if (!_pipController && _playerLayer && [AVPictureInPictureController isPictureInPictureSupported]) {
783+
// Create new controller passing reference to the AVPlayerLayer
784+
_pipController = [[AVPictureInPictureController alloc] initWithPlayerLayer:_playerLayer];
785+
_pipController.delegate = self;
787786
}
788787
}
789788

@@ -1383,14 +1382,18 @@ - (void)removeFromSuperview
13831382
#pragma mark - Picture in Picture
13841383

13851384
- (void)pictureInPictureControllerDidStopPictureInPicture:(AVPictureInPictureController *)pictureInPictureController {
1386-
if (self.onIsPictureInPictureActive && _pipController) {
1387-
self.onIsPictureInPictureActive(@{@"active": [NSNumber numberWithBool:false]});
1385+
if (self.onPictureInPictureStatusChanged) {
1386+
self.onPictureInPictureStatusChanged(@{
1387+
@"isActive": [NSNumber numberWithBool:false]
1388+
});
13881389
}
13891390
}
13901391

13911392
- (void)pictureInPictureControllerDidStartPictureInPicture:(AVPictureInPictureController *)pictureInPictureController {
1392-
if (self.onIsPictureInPictureActive && _pipController) {
1393-
self.onIsPictureInPictureActive(@{@"active": [NSNumber numberWithBool:true]});
1393+
if (self.onPictureInPictureStatusChanged) {
1394+
self.onPictureInPictureStatusChanged(@{
1395+
@"isActive": [NSNumber numberWithBool:true]
1396+
});
13941397
}
13951398
}
13961399

@@ -1408,6 +1411,9 @@ - (void)pictureInPictureController:(AVPictureInPictureController *)pictureInPict
14081411

14091412
- (void)pictureInPictureController:(AVPictureInPictureController *)pictureInPictureController restoreUserInterfaceForPictureInPictureStopWithCompletionHandler:(void (^)(BOOL))completionHandler {
14101413
NSAssert(_restoreUserInterfaceForPIPStopCompletionHandler == NULL, @"restoreUserInterfaceForPIPStopCompletionHandler was not called after picture in picture was exited.");
1414+
if (self.needsToRestoreUserInterfaceForPictureInPictureStop) {
1415+
self.needsToRestoreUserInterfaceForPictureInPictureStop(@{});
1416+
}
14111417
_restoreUserInterfaceForPIPStopCompletionHandler = completionHandler;
14121418
}
14131419

ios/Video/RCTVideoManager.m

+3-3
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ - (dispatch_queue_t)methodQueue
3232
RCT_EXPORT_VIEW_PROPERTY(volume, float);
3333
RCT_EXPORT_VIEW_PROPERTY(playInBackground, BOOL);
3434
RCT_EXPORT_VIEW_PROPERTY(playWhenInactive, BOOL);
35+
RCT_EXPORT_VIEW_PROPERTY(pictureInPicture, BOOL);
3536
RCT_EXPORT_VIEW_PROPERTY(ignoreSilentSwitch, NSString);
3637
RCT_EXPORT_VIEW_PROPERTY(rate, float);
3738
RCT_EXPORT_VIEW_PROPERTY(seek, NSDictionary);
3839
RCT_EXPORT_VIEW_PROPERTY(currentTime, float);
3940
RCT_EXPORT_VIEW_PROPERTY(fullscreen, BOOL);
4041
RCT_EXPORT_VIEW_PROPERTY(fullscreenOrientation, NSString);
4142
RCT_EXPORT_VIEW_PROPERTY(progressUpdateInterval, float);
42-
RCT_EXPORT_VIEW_PROPERTY(pictureInPicture, BOOL);
4343
RCT_EXPORT_VIEW_PROPERTY(restoreUserInterfaceForPIPStopCompletionHandler, BOOL);
4444
/* Should support: onLoadStart, onLoad, and onError to stay consistent with Image */
4545
RCT_EXPORT_VIEW_PROPERTY(onVideoLoadStart, RCTBubblingEventBlock);
@@ -60,8 +60,8 @@ - (dispatch_queue_t)methodQueue
6060
RCT_EXPORT_VIEW_PROPERTY(onPlaybackResume, RCTBubblingEventBlock);
6161
RCT_EXPORT_VIEW_PROPERTY(onPlaybackRateChange, RCTBubblingEventBlock);
6262
RCT_EXPORT_VIEW_PROPERTY(onVideoExternalPlaybackChange, RCTBubblingEventBlock);
63-
RCT_EXPORT_VIEW_PROPERTY(onIsPictureInPictureSupported, RCTBubblingEventBlock);
64-
RCT_EXPORT_VIEW_PROPERTY(onIsPictureInPictureActive, RCTBubblingEventBlock);
63+
RCT_EXPORT_VIEW_PROPERTY(onPictureInPictureStatusChanged, RCTBubblingEventBlock);
64+
RCT_EXPORT_VIEW_PROPERTY(needsToRestoreUserInterfaceForPictureInPictureStop, RCTBubblingEventBlock);
6565

6666
- (NSDictionary *)constantsToExport
6767
{

0 commit comments

Comments
 (0)