feat: add setSource API function fix ads playback (#4185)
* feat: add setSource API function fix ads playback
This commit is contained in:
		@@ -93,6 +93,13 @@ public final class ExoPlayerView extends FrameLayout implements AdViewProvider {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void showAds() {
 | 
			
		||||
        adOverlayFrameLayout.setVisibility(View.GONE);
 | 
			
		||||
    }
 | 
			
		||||
    public void hideAds() {
 | 
			
		||||
        adOverlayFrameLayout.setVisibility(View.VISIBLE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void clearVideoView() {
 | 
			
		||||
        if (surfaceView instanceof TextureView) {
 | 
			
		||||
            player.clearVideoTextureView((TextureView) surfaceView);
 | 
			
		||||
@@ -189,7 +196,7 @@ public final class ExoPlayerView extends FrameLayout implements AdViewProvider {
 | 
			
		||||
        surfaceView.setAlpha(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void updateShutterViewVisibility() {
 | 
			
		||||
    public void updateShutterViewVisibility() {
 | 
			
		||||
        if (this.hideShutterView) {
 | 
			
		||||
            hideShutterView();
 | 
			
		||||
        } else {
 | 
			
		||||
 
 | 
			
		||||
@@ -735,22 +735,28 @@ public class ReactExoplayerView extends FrameLayout implements
 | 
			
		||||
        ReactExoplayerView self = this;
 | 
			
		||||
        Activity activity = themedReactContext.getCurrentActivity();
 | 
			
		||||
        // This ensures all props have been settled, to avoid async racing conditions.
 | 
			
		||||
        Source runningSource = source;
 | 
			
		||||
        mainRunnable = () -> {
 | 
			
		||||
            if (viewHasDropped) {
 | 
			
		||||
            if (viewHasDropped && runningSource == source) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            try {
 | 
			
		||||
                if (runningSource.getUri() == null) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                if (player == null) {
 | 
			
		||||
                    // Initialize core configuration and listeners
 | 
			
		||||
                    initializePlayerCore(self);
 | 
			
		||||
                }
 | 
			
		||||
                if (playerNeedsSource && source.getUri() != null) {
 | 
			
		||||
                if (playerNeedsSource) {
 | 
			
		||||
                    // Will force display of shutter view if needed
 | 
			
		||||
                    exoPlayerView.updateShutterViewVisibility();
 | 
			
		||||
                    exoPlayerView.invalidateAspectRatio();
 | 
			
		||||
                    // DRM session manager creation must be done on a different thread to prevent crashes so we start a new thread
 | 
			
		||||
                    ExecutorService es = Executors.newSingleThreadExecutor();
 | 
			
		||||
                    es.execute(() -> {
 | 
			
		||||
                        // DRM initialization must run on a different thread
 | 
			
		||||
                        if (viewHasDropped) {
 | 
			
		||||
                        if (viewHasDropped && runningSource == source) {
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                        if (activity == null) {
 | 
			
		||||
@@ -761,12 +767,12 @@ public class ReactExoplayerView extends FrameLayout implements
 | 
			
		||||
 | 
			
		||||
                        // Initialize handler to run on the main thread
 | 
			
		||||
                        activity.runOnUiThread(() -> {
 | 
			
		||||
                            if (viewHasDropped) {
 | 
			
		||||
                            if (viewHasDropped && runningSource == source) {
 | 
			
		||||
                                return;
 | 
			
		||||
                            }
 | 
			
		||||
                            try {
 | 
			
		||||
                                // Source initialization must run on the main thread
 | 
			
		||||
                                initializePlayerSource();
 | 
			
		||||
                                initializePlayerSource(runningSource);
 | 
			
		||||
                            } catch (Exception ex) {
 | 
			
		||||
                                self.playerNeedsSource = true;
 | 
			
		||||
                                DebugLog.e(TAG, "Failed to initialize Player! 1");
 | 
			
		||||
@@ -776,8 +782,8 @@ public class ReactExoplayerView extends FrameLayout implements
 | 
			
		||||
                            }
 | 
			
		||||
                        });
 | 
			
		||||
                    });
 | 
			
		||||
                } else if (source.getUri() != null) {
 | 
			
		||||
                    initializePlayerSource();
 | 
			
		||||
                } else if (runningSource == source) {
 | 
			
		||||
                    initializePlayerSource(runningSource);
 | 
			
		||||
                }
 | 
			
		||||
            } catch (Exception ex) {
 | 
			
		||||
                self.playerNeedsSource = true;
 | 
			
		||||
@@ -816,6 +822,11 @@ public class ReactExoplayerView extends FrameLayout implements
 | 
			
		||||
                        .setEnableDecoderFallback(true)
 | 
			
		||||
                        .forceEnableMediaCodecAsynchronousQueueing();
 | 
			
		||||
 | 
			
		||||
        DefaultMediaSourceFactory mediaSourceFactory = new DefaultMediaSourceFactory(mediaDataSourceFactory);
 | 
			
		||||
        if (useCache) {
 | 
			
		||||
            mediaSourceFactory.setDataSourceFactory(RNVSimpleCache.INSTANCE.getCacheFactory(buildHttpDataSourceFactory(true)));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ImaSdkSettings imaSdkSettings = ImaSdkFactory.getInstance().createImaSdkSettings();
 | 
			
		||||
        imaSdkSettings.setLanguage(adLanguage);
 | 
			
		||||
 | 
			
		||||
@@ -826,14 +837,7 @@ public class ReactExoplayerView extends FrameLayout implements
 | 
			
		||||
                .setAdEventListener(this)
 | 
			
		||||
                .setAdErrorListener(this)
 | 
			
		||||
                .build();
 | 
			
		||||
        DefaultMediaSourceFactory mediaSourceFactory = new DefaultMediaSourceFactory(mediaDataSourceFactory);
 | 
			
		||||
        if (useCache) {
 | 
			
		||||
            mediaSourceFactory.setDataSourceFactory(RNVSimpleCache.INSTANCE.getCacheFactory(buildHttpDataSourceFactory(true)));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (adsLoader != null) {
 | 
			
		||||
        mediaSourceFactory.setLocalAdInsertionComponents(unusedAdTagUri -> adsLoader, exoPlayerView);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        player = new ExoPlayer.Builder(getContext(), renderersFactory)
 | 
			
		||||
                .setTrackSelector(self.trackSelector)
 | 
			
		||||
@@ -846,6 +850,7 @@ public class ReactExoplayerView extends FrameLayout implements
 | 
			
		||||
        player.addListener(self);
 | 
			
		||||
        player.setVolume(muted ? 0.f : audioVolume * 1);
 | 
			
		||||
        exoPlayerView.setPlayer(player);
 | 
			
		||||
 | 
			
		||||
        if (adsLoader != null) {
 | 
			
		||||
            adsLoader.setPlayer(player);
 | 
			
		||||
        }
 | 
			
		||||
@@ -884,31 +889,28 @@ public class ReactExoplayerView extends FrameLayout implements
 | 
			
		||||
        return drmSessionManager;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void initializePlayerSource() {
 | 
			
		||||
        if (source.getUri() == null) {
 | 
			
		||||
    private void initializePlayerSource(Source runningSource) {
 | 
			
		||||
        if (runningSource.getUri() == null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        /// init DRM
 | 
			
		||||
        DrmSessionManager drmSessionManager = initializePlayerDrm();
 | 
			
		||||
        if (drmSessionManager == null && source.getDrmProps() != null && source.getDrmProps().getDrmType() != null) {
 | 
			
		||||
        if (drmSessionManager == null && runningSource.getDrmProps() != null && runningSource.getDrmProps().getDrmType() != null) {
 | 
			
		||||
            // Failed to initialize DRM session manager - cannot continue
 | 
			
		||||
            DebugLog.e(TAG, "Failed to initialize DRM Session Manager Framework!");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        // init source to manage ads and external text tracks
 | 
			
		||||
        ArrayList<MediaSource> mediaSourceList = buildTextSources();
 | 
			
		||||
        MediaSource videoSource = buildMediaSource(source.getUri(), source.getExtension(), drmSessionManager, source.getCropStartMs(), source.getCropEndMs());
 | 
			
		||||
        MediaSource videoSource = buildMediaSource(runningSource.getUri(), runningSource.getExtension(), drmSessionManager, runningSource.getCropStartMs(), runningSource.getCropEndMs());
 | 
			
		||||
        MediaSource mediaSourceWithAds = null;
 | 
			
		||||
        if (adTagUrl != null && adsLoader != null) {
 | 
			
		||||
        if (adTagUrl != null && BuildConfig.USE_EXOPLAYER_IMA) {
 | 
			
		||||
            DefaultMediaSourceFactory mediaSourceFactory = new DefaultMediaSourceFactory(mediaDataSourceFactory)
 | 
			
		||||
                    .setLocalAdInsertionComponents(unusedAdTagUri -> adsLoader, exoPlayerView);
 | 
			
		||||
            DataSpec adTagDataSpec = new DataSpec(adTagUrl);
 | 
			
		||||
            mediaSourceWithAds = new AdsMediaSource(videoSource, adTagDataSpec, ImmutableList.of(source.getUri(), adTagUrl), mediaSourceFactory, adsLoader, exoPlayerView);
 | 
			
		||||
        } else {
 | 
			
		||||
            if (adTagUrl == null && adsLoader != null) {
 | 
			
		||||
                adsLoader.release();
 | 
			
		||||
                adsLoader = null;
 | 
			
		||||
            }
 | 
			
		||||
            DebugLog.w(TAG, "ads " + adTagUrl);
 | 
			
		||||
            mediaSourceWithAds = new AdsMediaSource(videoSource, adTagDataSpec, ImmutableList.of(runningSource.getUri(), adTagUrl), mediaSourceFactory, adsLoader, exoPlayerView);
 | 
			
		||||
            exoPlayerView.showAds();
 | 
			
		||||
        }
 | 
			
		||||
        MediaSource mediaSource;
 | 
			
		||||
        if (mediaSourceList.isEmpty()) {
 | 
			
		||||
@@ -943,8 +945,8 @@ public class ReactExoplayerView extends FrameLayout implements
 | 
			
		||||
        if (haveResumePosition) {
 | 
			
		||||
            player.seekTo(resumeWindow, resumePosition);
 | 
			
		||||
            player.setMediaSource(mediaSource, false);
 | 
			
		||||
        } else if (source.getStartPositionMs() > 0) {
 | 
			
		||||
            player.setMediaSource(mediaSource, source.getStartPositionMs());
 | 
			
		||||
        } else if (runningSource.getStartPositionMs() > 0) {
 | 
			
		||||
            player.setMediaSource(mediaSource, runningSource.getStartPositionMs());
 | 
			
		||||
        } else {
 | 
			
		||||
            player.setMediaSource(mediaSource, true);
 | 
			
		||||
        }
 | 
			
		||||
@@ -1243,10 +1245,6 @@ public class ReactExoplayerView extends FrameLayout implements
 | 
			
		||||
 | 
			
		||||
    private void releasePlayer() {
 | 
			
		||||
        if (player != null) {
 | 
			
		||||
            if (adsLoader != null) {
 | 
			
		||||
                adsLoader.setPlayer(null);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if(playbackServiceBinder != null) {
 | 
			
		||||
                playbackServiceBinder.getService().unregisterPlayer(player);
 | 
			
		||||
                themedReactContext.unbindService(playbackServiceConnection);
 | 
			
		||||
@@ -1903,20 +1901,22 @@ public class ReactExoplayerView extends FrameLayout implements
 | 
			
		||||
            if (!isSourceEqual) {
 | 
			
		||||
                reloadSource();
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            clearSrc();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void clearSrc() {
 | 
			
		||||
        if (source.getUri() != null) {
 | 
			
		||||
            if (player != null) {
 | 
			
		||||
                player.stop();
 | 
			
		||||
                player.clearMediaItems();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        exoPlayerView.hideAds();
 | 
			
		||||
        this.source = new Source();
 | 
			
		||||
        this.mediaDataSourceFactory = null;
 | 
			
		||||
        clearResumePosition();
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setProgressUpdateInterval(final float progressUpdateInterval) {
 | 
			
		||||
        mProgressUpdateInterval = progressUpdateInterval;
 | 
			
		||||
@@ -1927,6 +1927,7 @@ public class ReactExoplayerView extends FrameLayout implements
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setAdTagUrl(final Uri uri) {
 | 
			
		||||
        DebugLog.w(TAG, "setAdTagUrl" + uri);
 | 
			
		||||
        adTagUrl = uri;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -89,12 +89,7 @@ class ReactExoplayerViewManager(private val config: ReactExoplayerConfig) : View
 | 
			
		||||
    @ReactProp(name = PROP_SRC)
 | 
			
		||||
    fun setSrc(videoView: ReactExoplayerView, src: ReadableMap?) {
 | 
			
		||||
        val context = videoView.context.applicationContext
 | 
			
		||||
        val source = Source.parse(src, context)
 | 
			
		||||
        if (source.uri == null) {
 | 
			
		||||
            videoView.clearSrc()
 | 
			
		||||
        } else {
 | 
			
		||||
            videoView.setSrc(source)
 | 
			
		||||
        }
 | 
			
		||||
        videoView.setSrc(Source.parse(src, context))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ReactProp(name = PROP_AD_TAG_URL)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,12 @@
 | 
			
		||||
package com.brentvatne.react
 | 
			
		||||
 | 
			
		||||
import com.brentvatne.common.api.Source
 | 
			
		||||
import com.brentvatne.exoplayer.ReactExoplayerView
 | 
			
		||||
import com.facebook.react.bridge.Promise
 | 
			
		||||
import com.facebook.react.bridge.ReactApplicationContext
 | 
			
		||||
import com.facebook.react.bridge.ReactContextBaseJavaModule
 | 
			
		||||
import com.facebook.react.bridge.ReactMethod
 | 
			
		||||
import com.facebook.react.bridge.ReadableMap
 | 
			
		||||
import com.facebook.react.bridge.UiThreadUtil
 | 
			
		||||
import com.facebook.react.uimanager.UIManagerHelper
 | 
			
		||||
import com.facebook.react.uimanager.common.UIManagerType
 | 
			
		||||
@@ -63,6 +65,13 @@ class VideoManagerModule(reactContext: ReactApplicationContext?) : ReactContextB
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ReactMethod
 | 
			
		||||
    fun setSourceCmd(reactTag: Int, source: ReadableMap?) {
 | 
			
		||||
        performOnPlayerView(reactTag) {
 | 
			
		||||
            it?.setSrc(Source.parse(source, reactApplicationContext))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ReactMethod
 | 
			
		||||
    fun getCurrentPosition(reactTag: Int, promise: Promise) {
 | 
			
		||||
        performOnPlayerView(reactTag) {
 | 
			
		||||
 
 | 
			
		||||
@@ -115,6 +115,16 @@ This function will change the volume exactly like [volume](./props#volume) prope
 | 
			
		||||
This function retrieves and returns the precise current position of the video playback, measured in seconds.
 | 
			
		||||
This function will throw an error if player is not initialized.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### `setSource`
 | 
			
		||||
 | 
			
		||||
<PlatformsList types={['Android', 'iOS']} />
 | 
			
		||||
 | 
			
		||||
`setSource(source: ReactVideoSource): Promise<void>`
 | 
			
		||||
 | 
			
		||||
This function will change the source exactly like [source](./props#source) property.
 | 
			
		||||
Changing source with this function will overide source provided as props. 
 | 
			
		||||
 | 
			
		||||
### `setFullScreen`
 | 
			
		||||
 | 
			
		||||
<PlatformsList types={['Android', 'iOS']} />
 | 
			
		||||
 
 | 
			
		||||
@@ -252,6 +252,10 @@ const VideoPlayer: FC<Props> = ({}) => {
 | 
			
		||||
    cacheSizeMB: useCache ? 200 : 0,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    videoRef.current?.setSource(currentSrc)
 | 
			
		||||
  }, [currentSrc])
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <View style={styles.container}>
 | 
			
		||||
      <StatusBar animated={true} backgroundColor="black" hidden={false} />
 | 
			
		||||
@@ -261,7 +265,7 @@ const VideoPlayer: FC<Props> = ({}) => {
 | 
			
		||||
          <Video
 | 
			
		||||
            showNotificationControls={showNotificationControls}
 | 
			
		||||
            ref={videoRef}
 | 
			
		||||
            source={currentSrc as ReactVideoSource}
 | 
			
		||||
            // source={currentSrc as ReactVideoSource}
 | 
			
		||||
            adTagUrl={additional?.adTagUrl}
 | 
			
		||||
            drm={additional?.drm}
 | 
			
		||||
            style={viewStyle}
 | 
			
		||||
 
 | 
			
		||||
@@ -75,6 +75,7 @@ RCT_EXTERN_METHOD(setLicenseResultErrorCmd : (nonnull NSNumber*)reactTag error :
 | 
			
		||||
RCT_EXTERN_METHOD(setPlayerPauseStateCmd : (nonnull NSNumber*)reactTag paused : (nonnull BOOL)paused)
 | 
			
		||||
RCT_EXTERN_METHOD(setVolumeCmd : (nonnull NSNumber*)reactTag volume : (nonnull float*)volume)
 | 
			
		||||
RCT_EXTERN_METHOD(setFullScreenCmd : (nonnull NSNumber*)reactTag fullscreen : (nonnull BOOL)fullScreen)
 | 
			
		||||
RCT_EXTERN_METHOD(setSourceCmd : (nonnull NSNumber*)reactTag source : (NSDictionary*)source)
 | 
			
		||||
 | 
			
		||||
RCT_EXTERN_METHOD(save
 | 
			
		||||
                  : (nonnull NSNumber*)reactTag options
 | 
			
		||||
 
 | 
			
		||||
@@ -72,6 +72,13 @@ class RCTVideoManager: RCTViewManager {
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @objc(setSourceCmd:source:)
 | 
			
		||||
    func setSourceCmd(_ reactTag: NSNumber, source: NSDictionary) {
 | 
			
		||||
        performOnVideoView(withReactTag: reactTag, callback: { videoView in
 | 
			
		||||
            videoView?.setSrc(source)
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @objc(save:options:resolve:reject:)
 | 
			
		||||
    func save(_ reactTag: NSNumber, options: NSDictionary, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
 | 
			
		||||
        performOnVideoView(withReactTag: reactTag, callback: { videoView in
 | 
			
		||||
 
 | 
			
		||||
@@ -53,6 +53,7 @@ import type {
 | 
			
		||||
  OnReceiveAdEventData,
 | 
			
		||||
  ReactVideoProps,
 | 
			
		||||
  CmcdData,
 | 
			
		||||
  ReactVideoSource,
 | 
			
		||||
} from './types';
 | 
			
		||||
 | 
			
		||||
export interface VideoRef {
 | 
			
		||||
@@ -66,6 +67,7 @@ export interface VideoRef {
 | 
			
		||||
  ) => void;
 | 
			
		||||
  setVolume: (volume: number) => void;
 | 
			
		||||
  setFullScreen: (fullScreen: boolean) => void;
 | 
			
		||||
  setSource: (source?: ReactVideoSource) => void;
 | 
			
		||||
  save: (options: object) => Promise<VideoSaveData> | void;
 | 
			
		||||
  getCurrentPosition: () => Promise<number>;
 | 
			
		||||
}
 | 
			
		||||
@@ -157,11 +159,12 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
 | 
			
		||||
      setRestoreUserInterfaceForPIPStopCompletionHandler,
 | 
			
		||||
    ] = useState<boolean | undefined>();
 | 
			
		||||
 | 
			
		||||
    const src = useMemo<VideoSrc | undefined>(() => {
 | 
			
		||||
      if (!source) {
 | 
			
		||||
    const sourceToUnternalSource = useCallback(
 | 
			
		||||
      (_source?: ReactVideoSource) => {
 | 
			
		||||
        if (!_source) {
 | 
			
		||||
          return undefined;
 | 
			
		||||
        }
 | 
			
		||||
      const resolvedSource = resolveAssetSourceForVideo(source);
 | 
			
		||||
        const resolvedSource = resolveAssetSourceForVideo(_source);
 | 
			
		||||
        let uri = resolvedSource.uri || '';
 | 
			
		||||
        if (uri && uri.match(/^\//)) {
 | 
			
		||||
          uri = `file://${uri}`;
 | 
			
		||||
@@ -177,8 +180,8 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
 | 
			
		||||
          )
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
      const selectedDrm = source.drm || drm;
 | 
			
		||||
      const _textTracks = source.textTracks || textTracks;
 | 
			
		||||
        const selectedDrm = _source.drm || drm;
 | 
			
		||||
        const _textTracks = _source.textTracks || textTracks;
 | 
			
		||||
        const _drm = !selectedDrm
 | 
			
		||||
          ? undefined
 | 
			
		||||
          : {
 | 
			
		||||
@@ -220,7 +223,7 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const selectedContentStartTime =
 | 
			
		||||
        source.contentStartTime || contentStartTime;
 | 
			
		||||
          _source.contentStartTime || contentStartTime;
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
          uri,
 | 
			
		||||
@@ -242,13 +245,19 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
 | 
			
		||||
          textTracksAllowChunklessPreparation:
 | 
			
		||||
            resolvedSource.textTracksAllowChunklessPreparation,
 | 
			
		||||
        };
 | 
			
		||||
    }, [
 | 
			
		||||
      },
 | 
			
		||||
      [
 | 
			
		||||
        contentStartTime,
 | 
			
		||||
        drm,
 | 
			
		||||
        localSourceEncryptionKeyScheme,
 | 
			
		||||
        source,
 | 
			
		||||
        textTracks,
 | 
			
		||||
      contentStartTime,
 | 
			
		||||
      localSourceEncryptionKeyScheme,
 | 
			
		||||
    ]);
 | 
			
		||||
      ],
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const src = useMemo<VideoSrc | undefined>(() => {
 | 
			
		||||
      return sourceToUnternalSource(source);
 | 
			
		||||
    }, [sourceToUnternalSource, source]);
 | 
			
		||||
 | 
			
		||||
    const _selectedTextTrack = useMemo(() => {
 | 
			
		||||
      if (!selectedTextTrack) {
 | 
			
		||||
@@ -370,6 +379,16 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
 | 
			
		||||
      );
 | 
			
		||||
    }, []);
 | 
			
		||||
 | 
			
		||||
    const setSource = useCallback(
 | 
			
		||||
      (_source?: ReactVideoSource) => {
 | 
			
		||||
        return NativeVideoManager.setSourceCmd(
 | 
			
		||||
          getReactTag(nativeRef),
 | 
			
		||||
          sourceToUnternalSource(_source),
 | 
			
		||||
        );
 | 
			
		||||
      },
 | 
			
		||||
      [sourceToUnternalSource],
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const presentFullscreenPlayer = useCallback(
 | 
			
		||||
      () => setFullScreen(true),
 | 
			
		||||
      [setFullScreen],
 | 
			
		||||
@@ -628,6 +647,7 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
 | 
			
		||||
        setVolume,
 | 
			
		||||
        getCurrentPosition,
 | 
			
		||||
        setFullScreen,
 | 
			
		||||
        setSource,
 | 
			
		||||
      }),
 | 
			
		||||
      [
 | 
			
		||||
        seek,
 | 
			
		||||
@@ -640,6 +660,7 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
 | 
			
		||||
        setVolume,
 | 
			
		||||
        getCurrentPosition,
 | 
			
		||||
        setFullScreen,
 | 
			
		||||
        setSource,
 | 
			
		||||
      ],
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@ export interface VideoManagerType {
 | 
			
		||||
    licenseUrl: string,
 | 
			
		||||
  ) => Promise<void>;
 | 
			
		||||
  setFullScreenCmd: (reactTag: Int32, fullScreen: boolean) => Promise<void>;
 | 
			
		||||
  setSourceCmd: (reactTag: Int32, source?: UnsafeObject) => Promise<void>;
 | 
			
		||||
  setVolumeCmd: (reactTag: Int32, volume: number) => Promise<void>;
 | 
			
		||||
  save: (reactTag: Int32, option: UnsafeObject) => Promise<VideoSaveData>;
 | 
			
		||||
  getCurrentPosition: (reactTag: Int32) => Promise<Int32>;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user