Skip to content

Commit 8d33e3c

Browse files
aalzankiAbdulrahman Alzenki
authored andcommitted
Address some of the feedback from the pull reqeust
1 parent 4a16151 commit 8d33e3c

File tree

5 files changed

+79
-107
lines changed

5 files changed

+79
-107
lines changed

README.md

Lines changed: 37 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ var styles = StyleSheet.create({
271271
* [maxBitRate](#maxbitrate)
272272
* [muted](#muted)
273273
* [paused](#paused)
274+
* [pictureInPicture](#pictureinpicture)
274275
* [playInBackground](#playinbackground)
275276
* [playWhenInactive](#playwheninactive)
276277
* [poster](#poster)
@@ -298,22 +299,20 @@ var styles = StyleSheet.create({
298299
* [onFullscreenPlayerDidPresent](#onfullscreenplayerdidpresent)
299300
* [onFullscreenPlayerWillDismiss](#onfullscreenplayerwilldismiss)
300301
* [onFullscreenPlayerDidDismiss](#onfullscreenplayerdiddismiss)
301-
* [onIsPictureInPictureActive](#onispictureinpictureactive)
302-
* [onIsPictureInPictureSupported](#onispictureinpicturesupported)
303302
* [onLoad](#onload)
304303
* [onLoadStart](#onloadstart)
304+
* [onPictureInPictureStatusChanged](#onpictureinpicturestatuschanged)
305305
* [onProgress](#onprogress)
306306
* [onSeek](#onseek)
307+
* [onRestoreUserInterfaceForPictureInPictureStop](#onrestoreuserinterfaceforpictureinpicturestop)
307308
* [onTimedMetadata](#ontimedmetadata)
308309

309310
### Methods
310311
* [dismissFullscreenPlayer](#dismissfullscreenplayer)
311312
* [presentFullscreenPlayer](#presentfullscreenplayer)
312313
* [save](#save)
313314
* [restoreUserInterfaceForPictureInPictureStop](#restoreuserinterfaceforpictureinpicturestop)
314-
* [startPictureInPicture](#startpictureinpicture)
315315
* [seek](#seek)
316-
* [stopPictureInPicture](#stoppictureinpicture)
317316

318317
### Configurable props
319318

@@ -491,6 +490,13 @@ Controls whether the media is paused
491490

492491
Platforms: all
493492

493+
#### pictureInPicture
494+
Determine whether the media should played as picture in picture.
495+
* **false (default)** - Don't not play as picture in picture
496+
* **true** - Play the media as picture in picture
497+
498+
Platforms: iOS
499+
494500
#### playInBackground
495501
Determine whether the media should continue playing while the app is in the background. This allows customers to continue listening to the audio.
496502
* **false (default)** - Don't continue playing the media
@@ -866,38 +872,6 @@ Payload: none
866872

867873
Platforms: Android ExoPlayer, Android MediaPlayer, iOS
868874

869-
#### onIsPictureInPictureActive
870-
Callback function that is called when picture in picture becomes active or inactive.
871-
872-
Property | Type | Description
873-
--- | --- | ---
874-
active | boolean | Boolean indicating whether picture in picture is active
875-
876-
Example:
877-
```
878-
{
879-
active: true
880-
}
881-
```
882-
883-
Platforms: iOS
884-
885-
#### onIsPictureInPictureSupported
886-
Callback function that is called initially to determine whether or not picture in picture is supported.
887-
888-
Property | Type | Description
889-
--- | --- | ---
890-
supported | boolean | Boolean indicating whether picture in picture is supported
891-
892-
Example:
893-
```
894-
{
895-
supported: true
896-
}
897-
```
898-
899-
Platforms: iOS
900-
901875
#### onLoad
902876
Callback function that is called when the media is loaded and ready to play.
903877

@@ -963,6 +937,22 @@ Example:
963937

964938
Platforms: all
965939

940+
#### onPictureInPictureStatusChanged
941+
Callback function that is called when picture in picture becomes active or inactive.
942+
943+
Property | Type | Description
944+
--- | --- | ---
945+
isActive | boolean | Boolean indicating whether picture in picture is active
946+
947+
Example:
948+
```
949+
{
950+
isActive: true
951+
}
952+
```
953+
954+
Platforms: iOS
955+
966956
#### onProgress
967957
Callback function that is called every progressUpdateInterval seconds with info about which position the media is currently playing.
968958

@@ -1006,6 +996,13 @@ Both the currentTime & seekTime are reported because the video player may not se
1006996

1007997
Platforms: Android ExoPlayer, Android MediaPlayer, iOS, Windows UWP
1008998

999+
#### onRestoreUserInterfaceForPictureInPictureStop
1000+
Callback function that corresponds to Apple's [`restoreUserInterfaceForPictureInPictureStopWithCompletionHandler`](https://developer.apple.com/documentation/avkit/avpictureinpicturecontrollerdelegate/1614703-pictureinpicturecontroller?language=objc). Call `restoreUserInterfaceForPictureInPictureStopCompleted` inside of this function when done restoring the user interface.
1001+
1002+
Payload: none
1003+
1004+
Platforms: iOS
1005+
10091006
#### onTimedMetadata
10101007
Callback function that is called when timed metadata becomes available
10111008

@@ -1094,26 +1091,14 @@ Future:
10941091

10951092
Platforms: iOS
10961093

1097-
#### restoreUserInterfaceForPictureInPictureStop
1098-
`restoreUserInterfaceForPictureInPictureStop(restore)`
1094+
#### restoreUserInterfaceForPictureInPictureStopCompleted
1095+
`restoreUserInterfaceForPictureInPictureStopCompleted(restored)`
10991096

1100-
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.
1097+
This function corresponds to the completion handler in Apple's [restoreUserInterfaceForPictureInPictureStop](https://developer.apple.com/documentation/avkit/avpictureinpicturecontrollerdelegate/1614703-pictureinpicturecontroller?language=objc). IMPORTANT: This function must be called after `onRestoreUserInterfaceForPictureInPictureStop` is called.
11011098

11021099
Example:
11031100
```
1104-
this.player.restoreUserInterfaceForPictureInPictureStop(true);
1105-
```
1106-
1107-
Platforms: iOS
1108-
1109-
#### startPictureInPicture
1110-
`startPictureInPicture()`
1111-
1112-
Calling this function will start picture in picture if it is supported.
1113-
1114-
Example:
1115-
```
1116-
this.player.startPictureInPicture();
1101+
this.player.restoreUserInterfaceForPictureInPictureStopCompleted(true);
11171102
```
11181103

11191104
Platforms: iOS
@@ -1147,18 +1132,6 @@ this.player.seek(120, 50); // Seek to 2 minutes with +/- 50 milliseconds accurac
11471132

11481133
Platforms: iOS
11491134

1150-
#### stopPictureInPicture
1151-
`stopPictureInPicture()`
1152-
1153-
Calling this function will stop picture in picture if it is currently active.
1154-
1155-
Example:
1156-
```
1157-
this.player.stopPictureInPicture();
1158-
```
1159-
1160-
Platforms: iOS
1161-
11621135

11631136

11641137

Video.js

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -78,16 +78,8 @@ export default class Video extends Component {
7878
return await NativeModules.VideoManager.save(options, findNodeHandle(this._root));
7979
}
8080

81-
startPictureInPicture = () => {
82-
this.setNativeProps({ pictureInPicture: true });
83-
};
84-
85-
stopPictureInPicture = () => {
86-
this.setNativeProps({ pictureInPicture: false });
87-
};
88-
89-
restoreUserInterfaceForPictureInPictureStop = (restore) => {
90-
this.setNativeProps({ restoreUserInterfaceForPIPStopCompletionHandler: restore });
81+
restoreUserInterfaceForPictureInPictureStopCompleted = (restored) => {
82+
this.setNativeProps({ restoreUserInterfaceForPIPStopCompletionHandler: restored });
9183
};
9284

9385
_assignRoot = (component) => {
@@ -210,15 +202,15 @@ export default class Video extends Component {
210202
}
211203
};
212204

213-
_onIsPictureInPictureSupported = (event) => {
214-
if (this.props.onIsPictureInPictureSupported) {
215-
this.props.onIsPictureInPictureSupported(event.nativeEvent);
205+
_onPictureInPictureStatusChanged = (event) => {
206+
if (this.props.onPictureInPictureStatusChanged) {
207+
this.props.onPictureInPictureStatusChanged(event.nativeEvent);
216208
}
217209
};
218210

219-
_onIsPictureInPictureActive = (event) => {
220-
if (this.props.onIsPictureInPictureActive) {
221-
this.props.onIsPictureInPictureActive(event.nativeEvent);
211+
_onRestoreUserInterfaceForPictureInPictureStop = (event) => {
212+
if (this.props.onRestoreUserInterfaceForPictureInPictureStop) {
213+
this.props.onRestoreUserInterfaceForPictureInPictureStop();
222214
}
223215
};
224216

@@ -291,8 +283,8 @@ export default class Video extends Component {
291283
onPlaybackRateChange: this._onPlaybackRateChange,
292284
onAudioFocusChanged: this._onAudioFocusChanged,
293285
onAudioBecomingNoisy: this._onAudioBecomingNoisy,
294-
onIsPictureInPictureSupported: this._onIsPictureInPictureSupported,
295-
onIsPictureInPictureActive: this._onIsPictureInPictureActive,
286+
onPictureInPictureStatusChanged: this._onPictureInPictureStatusChanged,
287+
onRestoreUserInterfaceForPictureInPictureStop: this._onRestoreUserInterfaceForPictureInPictureStop,
296288
});
297289

298290
const posterStyle = {
@@ -415,6 +407,7 @@ Video.propTypes = {
415407
}),
416408
stereoPan: PropTypes.number,
417409
rate: PropTypes.number,
410+
pictureInPicture: PropTypes.bool,
418411
playInBackground: PropTypes.bool,
419412
playWhenInactive: PropTypes.bool,
420413
ignoreSilentSwitch: PropTypes.oneOf(['ignore', 'obey']),
@@ -446,8 +439,8 @@ Video.propTypes = {
446439
onPlaybackRateChange: PropTypes.func,
447440
onAudioFocusChanged: PropTypes.func,
448441
onAudioBecomingNoisy: PropTypes.func,
449-
onIsPictureInPictureSupported: PropTypes.func,
450-
onIsPictureInPictureActive: PropTypes.func,
442+
onPictureInPictureStatusChanged: PropTypes.func,
443+
needsToRestoreUserInterfaceForPictureInPictureStop: PropTypes.func,
451444
onExternalPlaybackChange: PropTypes.func,
452445

453446
/* Required by react-native */

ios/Video/RCTVideo.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
@property (nonatomic, copy) RCTBubblingEventBlock onPlaybackRateChange;
4040
@property (nonatomic, copy) RCTBubblingEventBlock onVideoExternalPlaybackChange;
4141
@property (nonatomic, copy) RCTBubblingEventBlock onIsPictureInPictureSupported;
42-
@property (nonatomic, copy) RCTBubblingEventBlock onIsPictureInPictureActive;
42+
@property (nonatomic, copy) RCTBubblingEventBlock onPictureInPictureStatusChanged;
43+
@property (nonatomic, copy) RCTBubblingEventBlock onRestoreUserInterfaceForPictureInPictureStop;
4344

4445
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
4546

ios/Video/RCTVideo.m

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ @implementation RCTVideo
6666
BOOL _playbackStalled;
6767
BOOL _playInBackground;
6868
BOOL _playWhenInactive;
69+
BOOL _pictureInPicture;
6970
NSString * _ignoreSilentSwitch;
7071
NSString * _resizeMode;
7172
BOOL _fullscreen;
@@ -102,6 +103,7 @@ - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
102103
_playInBackground = false;
103104
_allowsExternalPlayback = YES;
104105
_playWhenInactive = false;
106+
_pictureInPicture = false;
105107
_ignoreSilentSwitch = @"inherit"; // inherit, ignore, obey
106108
_restoreUserInterfaceForPIPStopCompletionHandler = NULL;
107109
#if __has_include(<react-native-video/RCTVideoCache.h>)
@@ -382,12 +384,6 @@ - (void)setSrc:(NSDictionary *)source
382384
@"target": self.reactTag
383385
});
384386
}
385-
386-
if (@available(iOS 9, *)) {
387-
if (self.onIsPictureInPictureSupported) {
388-
self.onIsPictureInPictureSupported(@{@"supported": [NSNumber numberWithBool:(bool)[AVPictureInPictureController isPictureInPictureSupported]]});
389-
}
390-
}
391387
}];
392388
});
393389
_videoLoadStarted = YES;
@@ -791,11 +787,16 @@ - (void)setPlayWhenInactive:(BOOL)playWhenInactive
791787

792788
- (void)setPictureInPicture:(BOOL)pictureInPicture
793789
{
794-
if (_pipController && pictureInPicture && ![_pipController isPictureInPictureActive]) {
790+
if (_pictureInPicture == pictureInPicture) {
791+
return;
792+
}
793+
794+
_pictureInPicture = pictureInPicture;
795+
if (_pipController && _pictureInPicture && ![_pipController isPictureInPictureActive]) {
795796
dispatch_async(dispatch_get_main_queue(), ^{
796797
[_pipController startPictureInPicture];
797798
});
798-
} else if (_pipController && !pictureInPicture && [_pipController isPictureInPictureActive]) {
799+
} else if (_pipController && !_pictureInPicture && [_pipController isPictureInPictureActive]) {
799800
dispatch_async(dispatch_get_main_queue(), ^{
800801
[_pipController stopPictureInPicture];
801802
});
@@ -811,12 +812,10 @@ - (void)setRestoreUserInterfaceForPIPStopCompletionHandler:(BOOL)restore
811812
}
812813

813814
- (void)setupPipController {
814-
if (@available(iOS 9, *)) {
815-
if (!_pipController && _playerLayer && [AVPictureInPictureController isPictureInPictureSupported]) {
816-
// Create new controller passing reference to the AVPlayerLayer
817-
_pipController = [[AVPictureInPictureController alloc] initWithPlayerLayer:_playerLayer];
818-
_pipController.delegate = self;
819-
}
815+
if (!_pipController && _playerLayer && [AVPictureInPictureController isPictureInPictureSupported]) {
816+
// Create new controller passing reference to the AVPlayerLayer
817+
_pipController = [[AVPictureInPictureController alloc] initWithPlayerLayer:_playerLayer];
818+
_pipController.delegate = self;
820819
}
821820
}
822821

@@ -1535,14 +1534,18 @@ - (NSString *)cacheDirectoryPath {
15351534
#pragma mark - Picture in Picture
15361535

15371536
- (void)pictureInPictureControllerDidStopPictureInPicture:(AVPictureInPictureController *)pictureInPictureController {
1538-
if (self.onIsPictureInPictureActive && _pipController) {
1539-
self.onIsPictureInPictureActive(@{@"active": [NSNumber numberWithBool:false]});
1537+
if (self.onPictureInPictureStatusChanged) {
1538+
self.onPictureInPictureStatusChanged(@{
1539+
@"isActive": [NSNumber numberWithBool:false]
1540+
});
15401541
}
15411542
}
15421543

15431544
- (void)pictureInPictureControllerDidStartPictureInPicture:(AVPictureInPictureController *)pictureInPictureController {
1544-
if (self.onIsPictureInPictureActive && _pipController) {
1545-
self.onIsPictureInPictureActive(@{@"active": [NSNumber numberWithBool:true]});
1545+
if (self.onPictureInPictureStatusChanged) {
1546+
self.onPictureInPictureStatusChanged(@{
1547+
@"isActive": [NSNumber numberWithBool:true]
1548+
});
15461549
}
15471550
}
15481551

@@ -1560,6 +1563,9 @@ - (void)pictureInPictureController:(AVPictureInPictureController *)pictureInPict
15601563

15611564
- (void)pictureInPictureController:(AVPictureInPictureController *)pictureInPictureController restoreUserInterfaceForPictureInPictureStopWithCompletionHandler:(void (^)(BOOL))completionHandler {
15621565
NSAssert(_restoreUserInterfaceForPIPStopCompletionHandler == NULL, @"restoreUserInterfaceForPIPStopCompletionHandler was not called after picture in picture was exited.");
1566+
if (self.onRestoreUserInterfaceForPictureInPictureStop) {
1567+
self.onRestoreUserInterfaceForPictureInPictureStop(@{});
1568+
}
15631569
_restoreUserInterfaceForPIPStopCompletionHandler = completionHandler;
15641570
}
15651571

ios/Video/RCTVideoManager.m

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#import "RCTVideoManager.h"
22
#import "RCTVideo.h"
33
#import <React/RCTBridge.h>
4-
#import <React/RCTUIManager.h>
54
#import <AVFoundation/AVFoundation.h>
65

76
@implementation RCTVideoManager
@@ -32,6 +31,7 @@ - (dispatch_queue_t)methodQueue
3231
RCT_EXPORT_VIEW_PROPERTY(volume, float);
3332
RCT_EXPORT_VIEW_PROPERTY(playInBackground, BOOL);
3433
RCT_EXPORT_VIEW_PROPERTY(playWhenInactive, BOOL);
34+
RCT_EXPORT_VIEW_PROPERTY(pictureInPicture, BOOL);
3535
RCT_EXPORT_VIEW_PROPERTY(ignoreSilentSwitch, NSString);
3636
RCT_EXPORT_VIEW_PROPERTY(rate, float);
3737
RCT_EXPORT_VIEW_PROPERTY(seek, NSDictionary);
@@ -42,7 +42,6 @@ - (dispatch_queue_t)methodQueue
4242
RCT_EXPORT_VIEW_PROPERTY(filter, NSString);
4343
RCT_EXPORT_VIEW_PROPERTY(filterEnabled, BOOL);
4444
RCT_EXPORT_VIEW_PROPERTY(progressUpdateInterval, float);
45-
RCT_EXPORT_VIEW_PROPERTY(pictureInPicture, BOOL);
4645
RCT_EXPORT_VIEW_PROPERTY(restoreUserInterfaceForPIPStopCompletionHandler, BOOL);
4746
/* Should support: onLoadStart, onLoad, and onError to stay consistent with Image */
4847
RCT_EXPORT_VIEW_PROPERTY(onVideoLoadStart, RCTBubblingEventBlock);
@@ -79,8 +78,8 @@ - (dispatch_queue_t)methodQueue
7978
}
8079
}];
8180
}
82-
RCT_EXPORT_VIEW_PROPERTY(onIsPictureInPictureSupported, RCTBubblingEventBlock);
83-
RCT_EXPORT_VIEW_PROPERTY(onIsPictureInPictureActive, RCTBubblingEventBlock);
81+
RCT_EXPORT_VIEW_PROPERTY(onPictureInPictureStatusChanged, RCTBubblingEventBlock);
82+
RCT_EXPORT_VIEW_PROPERTY(onRestoreUserInterfaceForPictureInPictureStop, RCTBubblingEventBlock);
8483

8584
- (NSDictionary *)constantsToExport
8685
{

0 commit comments

Comments
 (0)