From 85c9e8f99083a0909d4e66890fea4183a3ea4871 Mon Sep 17 00:00:00 2001 From: KrzysztofMoch Date: Mon, 18 Sep 2023 11:46:39 +0200 Subject: [PATCH 1/8] feat(ios): add playback functions to ref --- Video.js | 16 ++++++++++++++-- ios/Video/RCTVideoManager.m | 3 +++ ios/Video/RCTVideoManager.swift | 13 +++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Video.js b/Video.js index 3d342d02..f29cd4d7 100644 --- a/Video.js +++ b/Video.js @@ -14,8 +14,8 @@ const styles = StyleSheet.create({ }, }); -const { VideoDecoderProperties } = NativeModules -export { TextTrackType, FilterType, DRMType, VideoDecoderProperties } +const { VideoDecoderProperties } = NativeModules; +export { TextTrackType, FilterType, DRMType, VideoDecoderProperties }; export default class Video extends Component { @@ -81,6 +81,18 @@ export default class Video extends Component { return await NativeModules.VideoManager.save(options, findNodeHandle(this._root)); } + pause = async () => { + await this.setPlayerStatus(false); + }; + + play = async () => { + await this.setPlayerStatus(true); + }; + + setPlayerStatus = async (shouldPlay) => { + return await NativeModules.VideoManager.setPlayerStatus(shouldPlay, findNodeHandle(this._root)); + }; + restoreUserInterfaceForPictureInPictureStopCompleted = (restored) => { this.setNativeProps({ restoreUserInterfaceForPIPStopCompletionHandler: restored }); }; diff --git a/ios/Video/RCTVideoManager.m b/ios/Video/RCTVideoManager.m index 9bdf6101..83f49c4d 100644 --- a/ios/Video/RCTVideoManager.m +++ b/ios/Video/RCTVideoManager.m @@ -74,6 +74,9 @@ RCT_EXTERN_METHOD(setLicenseResult:(NSString *)license RCT_EXTERN_METHOD(setLicenseResultError(NSString *)error reactTag:(nonnull NSNumber *)reactTag) +RCT_EXTERN_METHOD(setPlayerStatus:(nonnull NSNumber *)shouldPlay + reactTag:(nonnull NSNumber *)reactTag) + RCT_EXTERN_METHOD(presentFullscreenPlayer reactTag:(nonnull NSNumber *)reactTag) diff --git a/ios/Video/RCTVideoManager.swift b/ios/Video/RCTVideoManager.swift index bfdec7a4..3e118d3c 100644 --- a/ios/Video/RCTVideoManager.swift +++ b/ios/Video/RCTVideoManager.swift @@ -71,6 +71,19 @@ class RCTVideoManager: RCTViewManager { }) } + @objc(setPlayerStatus:reactTag:) + func setPlayerStatus(shouldPlay: NSNumber, reactTag: NSNumber) -> Void { + bridge.uiManager.prependUIBlock({_ , viewRegistry in + let view = viewRegistry?[reactTag] + if !(view is RCTVideo) { + RCTLogError("Invalid view returned from registry, expecting RCTVideo, got: %@", String(describing: view)) + } else if let view = view as? RCTVideo { + let shouldPlay = shouldPlay.boolValue + view.setPaused(!shouldPlay) + } + }) + } + override func constantsToExport() -> [AnyHashable : Any]? { return [ "ScaleNone": AVLayerVideoGravity.resizeAspect, From 0066ec744c5acf5f32a46fa3c74fcd8bf52b0722 Mon Sep 17 00:00:00 2001 From: KrzysztofMoch Date: Mon, 18 Sep 2023 13:09:53 +0200 Subject: [PATCH 2/8] feat(android): add playback functions to ref --- .../exoplayer/ReactExoplayerView.java | 2 +- .../brentvatne/react/ReactVideoPackage.java | 10 +++-- .../brentvatne/react/VideoManagerModule.java | 39 +++++++++++++++++++ 3 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 android/src/main/java/com/brentvatne/react/VideoManagerModule.java diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index 8ef2afca..d62b38fc 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -116,7 +116,7 @@ import java.util.concurrent.TimeUnit; import java.lang.Integer; @SuppressLint("ViewConstructor") -class ReactExoplayerView extends FrameLayout implements +public class ReactExoplayerView extends FrameLayout implements LifecycleEventListener, Player.Listener, BandwidthMeter.EventListener, diff --git a/android/src/main/java/com/brentvatne/react/ReactVideoPackage.java b/android/src/main/java/com/brentvatne/react/ReactVideoPackage.java index 23bedad6..95afa512 100644 --- a/android/src/main/java/com/brentvatne/react/ReactVideoPackage.java +++ b/android/src/main/java/com/brentvatne/react/ReactVideoPackage.java @@ -9,6 +9,7 @@ import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.uimanager.ViewManager; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -25,9 +26,12 @@ public class ReactVideoPackage implements ReactPackage { @Override public List createNativeModules(ReactApplicationContext reactContext) { - return Collections.singletonList( - new VideoDecoderPropertiesModule(reactContext) - ); + List modules = new ArrayList(); + + modules.add(new VideoDecoderPropertiesModule(reactContext)); + modules.add(new VideoManagerModule(reactContext)); + + return modules; } // Deprecated RN 0.47 diff --git a/android/src/main/java/com/brentvatne/react/VideoManagerModule.java b/android/src/main/java/com/brentvatne/react/VideoManagerModule.java new file mode 100644 index 00000000..bf5b6c1f --- /dev/null +++ b/android/src/main/java/com/brentvatne/react/VideoManagerModule.java @@ -0,0 +1,39 @@ +package com.brentvatne.react; + +import android.view.View; + +import androidx.annotation.NonNull; + +import com.brentvatne.exoplayer.ReactExoplayerView; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.uimanager.UIManagerModule; + +public class VideoManagerModule extends ReactContextBaseJavaModule { + ReactApplicationContext reactContext; + + @NonNull + @Override + public String getName() { + return "VideoManager"; + } + + @ReactMethod + public void setPlayerStatus(Boolean shouldPlay, int reactTag) { + UIManagerModule uiManager = getReactApplicationContext().getNativeModule(UIManagerModule.class); + uiManager.prependUIBlock(manager -> { + View view = manager.resolveView(reactTag); + + if (view instanceof ReactExoplayerView) { + ReactExoplayerView videoView = (ReactExoplayerView) view; + videoView.setPausedModifier(!shouldPlay); + } + }); + } + + public VideoManagerModule(ReactApplicationContext reactContext) { + super(reactContext); + this.reactContext = reactContext; + } +} \ No newline at end of file From e7276922a27ae00718ffe25bf9bac404e637e4f9 Mon Sep 17 00:00:00 2001 From: KrzysztofMoch Date: Mon, 18 Sep 2023 14:21:20 +0200 Subject: [PATCH 3/8] docs: update API docs --- API.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/API.md b/API.md index 7b073748..6130bdb9 100644 --- a/API.md +++ b/API.md @@ -1643,6 +1643,47 @@ this.player.seek(120, 50); // Seek to 2 minutes with +/- 50 milliseconds accurac Platforms: iOS +### setPlayerStatus +`setPlayerStatus(shouldPlay: boolean): Promise` + +Play/Pause the video. + +Example: +``` +this.player.setPlayerStatus(true); // Play the video +this.player.setPlayerStatus(false); // Pause the video +``` + +platforms: Android, iOS + +### pause +`pause(): Promise` + +Pause the video. + +Example: +``` +this.player.pause(); +``` + +NOTE: This is the same as calling `setPlayerStatus(false)` + +Platforms: Android, iOS + +### play +`play(): Promise` + +Play the video. + +Example: +``` +this.player.play(); +``` + +NOTE: This is the same as calling `setPlayerStatus(true)` + +Platforms: Android, iOS + #### Static methods ### Video Decoding capabilities From c991a0e8f73572689cec379250667c11450046d8 Mon Sep 17 00:00:00 2001 From: KrzysztofMoch Date: Mon, 18 Sep 2023 16:20:14 +0200 Subject: [PATCH 4/8] chore: update basic example --- examples/basic/src/VideoPlayer.android.tsx | 500 +++++++++++---------- examples/basic/src/VideoPlayer.ios.tsx | 329 ++++++++------ 2 files changed, 462 insertions(+), 367 deletions(-) diff --git a/examples/basic/src/VideoPlayer.android.tsx b/examples/basic/src/VideoPlayer.android.tsx index a3206a84..a62ac563 100644 --- a/examples/basic/src/VideoPlayer.android.tsx +++ b/examples/basic/src/VideoPlayer.android.tsx @@ -1,8 +1,6 @@ 'use strict'; -import React, { - Component -} from 'react'; +import React, {Component, createRef} from 'react'; import { StyleSheet, @@ -14,12 +12,11 @@ import { ToastAndroid, } from 'react-native'; -import { Picker } from '@react-native-picker/picker' +import {Picker} from '@react-native-picker/picker'; -import Video, { VideoDecoderProperties, TextTrackType } from 'react-native-video'; +import Video, {TextTrackType, VideoDecoderProperties} from 'react-native-video'; class VideoPlayer extends Component { - state = { rate: 1, volume: 1, @@ -46,7 +43,7 @@ class VideoPlayer extends Component { showRNVControls: false, }; - seekerWidth = 0 + seekerWidth = 0; srcList = [ require('./broadchurch.mp4'), @@ -60,99 +57,95 @@ class VideoPlayer extends Component { }, { description: '(hls|live) red bull tv', - uri: 'https://rbmn-live.akamaized.net/hls/live/590964/BoRB-AT/master_928.m3u8' + uri: 'https://rbmn-live.akamaized.net/hls/live/590964/BoRB-AT/master_928.m3u8', }, { description: '(mp4|subtitles) demo with sintel Subtitles', - uri: - 'http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,source,id,as&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=51AF5F39AB0CEC3E5497CD9C900EBFEAECCCB5C7.8506521BFC350652163895D4C26DEE124209AA9E&key=ik0', + uri: 'http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,source,id,as&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=51AF5F39AB0CEC3E5497CD9C900EBFEAECCCB5C7.8506521BFC350652163895D4C26DEE124209AA9E&key=ik0', type: 'mpd', }, { description: 'invalid URL', - uri: - 'mmt://www.youtube.com', + uri: 'mmt://www.youtube.com', type: 'mpd', }, - { description: '(no url) Stopped playback', uri: undefined }, + {description: '(no url) Stopped playback', uri: undefined}, { description: '(no view) no View', noView: true, }, - ] + ]; - video: Video; + video = createRef