bitmovin-player-react-native 0.7.0 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -55,5 +55,6 @@ dependencies {
55
55
  implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
56
56
  implementation 'com.bitmovin.analytics:collector-bitmovin-player:2.12.1'
57
57
  implementation 'com.bitmovin.player:player:3.39.0'
58
- implementation 'com.facebook.react:react-native:0.69.10'
58
+ //noinspection GradleDynamicVersion
59
+ implementation 'com.facebook.react:react-native:+' // From node_modules
59
60
  }
@@ -106,6 +106,18 @@ class PlayerModule(private val context: ReactApplicationContext) : ReactContextB
106
106
  }
107
107
  }
108
108
 
109
+ /**
110
+ * Call `.timeShift(offset:)` on `nativeId`'s player.
111
+ * @param nativeId Target player Id.
112
+ * @param offset Offset time in seconds.
113
+ */
114
+ @ReactMethod
115
+ fun timeShift(nativeId: NativeId, offset: Double) {
116
+ uiManager()?.addUIBlock {
117
+ players[nativeId]?.timeShift(offset)
118
+ }
119
+ }
120
+
109
121
  /**
110
122
  * Call `.mute()` on `nativeId`'s player.
111
123
  * @param nativeId Target player Id.
@@ -362,6 +374,30 @@ class PlayerModule(private val context: ReactApplicationContext) : ReactContextB
362
374
  }
363
375
  }
364
376
 
377
+ /**
378
+ * The current time shift of the live stream in seconds. This value is always 0 if the active [source] is not a
379
+ * live stream or there is no active playback session.
380
+ * @param nativeId Target player id.
381
+ */
382
+ @ReactMethod
383
+ fun getTimeShift(nativeId: NativeId, promise: Promise) {
384
+ uiManager()?.addUIBlock {
385
+ promise.resolve(players[nativeId]?.timeShift)
386
+ }
387
+ }
388
+
389
+ /**
390
+ * The limit in seconds for time shifting. This value is either negative or 0 and it is always 0 if the active
391
+ * [source] is not a live stream or there is no active playback session.
392
+ * @param nativeId Target player id.
393
+ */
394
+ @ReactMethod
395
+ fun getMaxTimeShift(nativeId: NativeId, promise: Promise) {
396
+ uiManager()?.addUIBlock {
397
+ promise.resolve(players[nativeId]?.maxTimeShift)
398
+ }
399
+ }
400
+
365
401
  /**
366
402
  * Helper function that returns the initialized `UIManager` instance.
367
403
  */
@@ -34,6 +34,8 @@ private val EVENT_CLASS_TO_REACT_NATIVE_NAME_MAPPING = mapOf(
34
34
  PlayerEvent.PlaybackFinished::class to "playbackFinished",
35
35
  PlayerEvent.Seek::class to "seek",
36
36
  PlayerEvent.Seeked::class to "seeked",
37
+ PlayerEvent.TimeShift::class to "timeShift",
38
+ PlayerEvent.TimeShifted::class to "timeShifted",
37
39
  PlayerEvent.StallStarted::class to "stallStarted",
38
40
  PlayerEvent.StallEnded::class to "stallEnded",
39
41
  PlayerEvent.TimeChanged::class to "timeChanged",
@@ -2,6 +2,7 @@ package com.bitmovin.player.reactnative
2
2
 
3
3
  import android.os.Handler
4
4
  import android.os.Looper
5
+ import android.util.Log
5
6
  import android.view.ViewGroup.LayoutParams
6
7
  import com.bitmovin.player.PlayerView
7
8
  import com.bitmovin.player.reactnative.extensions.getBooleanOrNull
@@ -76,6 +77,8 @@ class RNPlayerViewManager(private val context: ReactApplicationContext) : Simple
76
77
  "playbackFinished" to "onPlaybackFinished",
77
78
  "seek" to "onSeek",
78
79
  "seeked" to "onSeeked",
80
+ "timeShift" to "onTimeShift",
81
+ "timeShifted" to "onTimeShifted",
79
82
  "stallStarted" to "onStallStarted",
80
83
  "stallEnded" to "onStallEnded",
81
84
  "timeChanged" to "onTimeChanged",
@@ -149,7 +152,7 @@ class RNPlayerViewManager(private val context: ReactApplicationContext) : Simple
149
152
  Commands.ATTACH_FULLSCREEN_BRIDGE.ordinal -> args?.getString(1)?.let { fullscreenBridgeId ->
150
153
  attachFullscreenBridge(view, fullscreenBridgeId)
151
154
  }
152
- Commands.SET_CUSTOM_MESSAGE_HANDLER_BRIDGE_ID.ordinal -> {
155
+ Commands.SET_CUSTOM_MESSAGE_HANDLER_BRIDGE_ID.ordinal -> {
153
156
  args?.getString(1)?.let { customMessageHandlerBridgeId ->
154
157
  setCustomMessageHandlerBridgeId(view, customMessageHandlerBridgeId)
155
158
  }
@@ -198,7 +201,13 @@ class RNPlayerViewManager(private val context: ReactApplicationContext) : Simple
198
201
  if (view.playerView != null) {
199
202
  view.player = player
200
203
  } else {
201
- val playerView = PlayerView(context, player)
204
+ // PlayerView has to be initialized with Activity context
205
+ val currentActivity = context.currentActivity
206
+ if (currentActivity == null) {
207
+ Log.e(MODULE_NAME, "Cannot create a PlayerView, because no activity is attached.")
208
+ return@post
209
+ }
210
+ val playerView = PlayerView(currentActivity, player)
202
211
  playerView.layoutParams = LayoutParams(
203
212
  LayoutParams.MATCH_PARENT,
204
213
  LayoutParams.MATCH_PARENT
@@ -401,6 +401,10 @@ class JsonConverter {
401
401
  json.putMap("from", fromSeekPosition(event.from))
402
402
  json.putMap("to", fromSeekPosition(event.to))
403
403
  }
404
+ if (event is PlayerEvent.TimeShift) {
405
+ json.putDouble("position", event.position)
406
+ json.putDouble("targetPosition", event.target)
407
+ }
404
408
  if (event is PlayerEvent.PictureInPictureAvailabilityChanged) {
405
409
  json.putBoolean("isPictureInPictureAvailable", event.isPictureInPictureAvailable)
406
410
  }
@@ -32,6 +32,17 @@ extension SeekEvent {
32
32
  }
33
33
  }
34
34
 
35
+ extension TimeShiftEvent {
36
+ func toJSON() -> [AnyHashable: Any] {
37
+ [
38
+ "name": name,
39
+ "timestamp": timestamp,
40
+ "position": position,
41
+ "targetPosition": target
42
+ ]
43
+ }
44
+ }
45
+
35
46
  extension TimeChangedEvent {
36
47
  func toJSON() -> [AnyHashable: Any] {
37
48
  ["name": name, "timestamp": timestamp, "currentTime": currentTime]
@@ -8,6 +8,7 @@ RCT_EXTERN_METHOD(unload:(NSString *)nativeId)
8
8
  RCT_EXTERN_METHOD(play:(NSString *)nativeId)
9
9
  RCT_EXTERN_METHOD(pause:(NSString *)nativeId)
10
10
  RCT_EXTERN_METHOD(seek:(NSString *)nativeId time:(nonnull NSNumber *)time)
11
+ RCT_EXTERN_METHOD(timeShift:(NSString *)nativeId offset:(nonnull NSNumber *)time)
11
12
  RCT_EXTERN_METHOD(mute:(NSString *)nativeId)
12
13
  RCT_EXTERN_METHOD(unmute:(NSString *)nativeId)
13
14
  RCT_EXTERN_METHOD(destroy:(NSString *)nativeId)
@@ -73,5 +74,13 @@ RCT_EXTERN_METHOD(
73
74
  isAd:(NSString *)nativeId
74
75
  resolver:(RCTPromiseResolveBlock)resolve
75
76
  rejecter:(RCTPromiseRejectBlock)reject)
77
+ RCT_EXTERN_METHOD(
78
+ getTimeShift:(NSString *)nativeId
79
+ resolver:(RCTPromiseResolveBlock)resolve
80
+ rejecter:(RCTPromiseRejectBlock)reject)
81
+ RCT_EXTERN_METHOD(
82
+ getMaxTimeShift:(NSString *)nativeId
83
+ resolver:(RCTPromiseResolveBlock)resolve
84
+ rejecter:(RCTPromiseRejectBlock)reject)
76
85
 
77
86
  @end
@@ -116,6 +116,18 @@ class PlayerModule: NSObject, RCTBridgeModule {
116
116
  self?.players[nativeId]?.seek(time: time.doubleValue)
117
117
  }
118
118
  }
119
+
120
+ /**
121
+ Sets `timeShift` on `nativeId`'s player.
122
+ - Parameter nativeId: Target player Id.
123
+ - Parameter offset: Offset to timeShift to in seconds.
124
+ */
125
+ @objc(timeShift:offset:)
126
+ func timeShift(_ nativeId: NativeId, offset: NSNumber) {
127
+ bridge.uiManager.addUIBlock { [weak self] _, _ in
128
+ self?.players[nativeId]?.timeShift = offset.doubleValue
129
+ }
130
+ }
119
131
 
120
132
  /**
121
133
  Call `.mute()` on `nativeId`'s player.
@@ -450,4 +462,39 @@ class PlayerModule: NSObject, RCTBridgeModule {
450
462
  resolve(self?.players[nativeId]?.isAd)
451
463
  }
452
464
  }
465
+
466
+ /**
467
+ The current time shift of the live stream in seconds. This value is always 0 if the active `source` is not a
468
+ live stream or there are no sources loaded.
469
+ - Parameter nativeId: Target player id.
470
+ - Parameter resolver: JS promise resolver.
471
+ - Parameter rejecter: JS promise rejecter.
472
+ */
473
+ @objc(getTimeShift:resolver:rejecter:)
474
+ func getTimeShift(
475
+ _ nativeId: NativeId,
476
+ resolver resolve: @escaping RCTPromiseResolveBlock,
477
+ rejecter reject: @escaping RCTPromiseRejectBlock
478
+ ) {
479
+ bridge.uiManager.addUIBlock { [weak self] _, _ in
480
+ resolve(self?.players[nativeId]?.timeShift)
481
+ }
482
+ }
483
+
484
+ /**
485
+ Returns the limit in seconds for time shift. Is either negative or 0. Is applicable for live streams only.
486
+ - Parameter nativeId: Target player id.
487
+ - Parameter resolver: JS promise resolver.
488
+ - Parameter rejecter: JS promise rejecter.
489
+ */
490
+ @objc(getMaxTimeShift:resolver:rejecter:)
491
+ func getMaxTimeShift(
492
+ _ nativeId: NativeId,
493
+ resolver resolve: @escaping RCTPromiseResolveBlock,
494
+ rejecter reject: @escaping RCTPromiseRejectBlock
495
+ ) {
496
+ bridge.uiManager.addUIBlock { [weak self] _, _ in
497
+ resolve(self?.players[nativeId]?.maxTimeShift)
498
+ }
499
+ }
453
500
  }
@@ -57,6 +57,14 @@ extension RNPlayerView: PlayerListener {
57
57
  onSeeked?(event.toJSON())
58
58
  }
59
59
 
60
+ func onTimeShift(_ event: TimeShiftEvent, player: Player) {
61
+ onTimeShift?(event.toJSON())
62
+ }
63
+
64
+ func onTimeShifted(_ event: TimeShiftedEvent, player: Player) {
65
+ onTimeShifted?(event.toJSON())
66
+ }
67
+
60
68
  func onStallStarted(_ event: StallStartedEvent, player: Player) {
61
69
  onStallStarted?(event.toJSON())
62
70
  }
@@ -17,6 +17,8 @@ class RNPlayerView: UIView {
17
17
  @objc var onPlaybackFinished: RCTBubblingEventBlock?
18
18
  @objc var onSeek: RCTBubblingEventBlock?
19
19
  @objc var onSeeked: RCTBubblingEventBlock?
20
+ @objc var onTimeShift: RCTBubblingEventBlock?
21
+ @objc var onTimeShifted: RCTBubblingEventBlock?
20
22
  @objc var onStallStarted: RCTBubblingEventBlock?
21
23
  @objc var onStallEnded: RCTBubblingEventBlock?
22
24
  @objc var onTimeChanged: RCTBubblingEventBlock?
@@ -16,6 +16,8 @@ RCT_EXPORT_VIEW_PROPERTY(onPlaying, RCTBubblingEventBlock)
16
16
  RCT_EXPORT_VIEW_PROPERTY(onPlaybackFinished, RCTBubblingEventBlock)
17
17
  RCT_EXPORT_VIEW_PROPERTY(onSeek, RCTBubblingEventBlock)
18
18
  RCT_EXPORT_VIEW_PROPERTY(onSeeked, RCTBubblingEventBlock)
19
+ RCT_EXPORT_VIEW_PROPERTY(onTimeShift, RCTBubblingEventBlock)
20
+ RCT_EXPORT_VIEW_PROPERTY(onTimeShifted, RCTBubblingEventBlock)
19
21
  RCT_EXPORT_VIEW_PROPERTY(onStallStarted, RCTBubblingEventBlock)
20
22
  RCT_EXPORT_VIEW_PROPERTY(onStallEnded, RCTBubblingEventBlock)
21
23
  RCT_EXPORT_VIEW_PROPERTY(onTimeChanged, RCTBubblingEventBlock)
package/lib/index.d.ts CHANGED
@@ -755,6 +755,26 @@ interface SeekEvent extends Event {
755
755
  */
756
756
  interface SeekedEvent extends Event {
757
757
  }
758
+ /**
759
+ * Emitted when the player starts time shifting.
760
+ * Only applies to live streams.
761
+ */
762
+ interface TimeShiftEvent extends Event {
763
+ /**
764
+ * The position from which we start the time shift
765
+ */
766
+ position: number;
767
+ /**
768
+ * The position to which we want to jump for the time shift
769
+ */
770
+ targetPosition: number;
771
+ }
772
+ /**
773
+ * Emitted when time shifting has finished and data is available to continue playback.
774
+ * Only applies to live streams.
775
+ */
776
+ interface TimeShiftedEvent extends Event {
777
+ }
758
778
  /**
759
779
  * Emitted when the player begins to stall and to buffer due to an empty buffer.
760
780
  */
@@ -1137,6 +1157,8 @@ interface EventProps {
1137
1157
  onReady: ReadyEvent;
1138
1158
  onSeek: SeekEvent;
1139
1159
  onSeeked: SeekedEvent;
1160
+ onTimeShift: TimeShiftEvent;
1161
+ onTimeShifted: TimeShiftedEvent;
1140
1162
  onStallStarted: StallStartedEvent;
1141
1163
  onStallEnded: StallEndedEvent;
1142
1164
  onSourceError: SourceErrorEvent;
@@ -1959,6 +1981,16 @@ declare class Player extends NativeInstance<PlayerConfig> {
1959
1981
  * @param time - The time to seek to in seconds.
1960
1982
  */
1961
1983
  seek: (time: number) => void;
1984
+ /**
1985
+ * Shifts the time to the given `offset` in seconds from the live edge. The resulting offset has to be within the
1986
+ * timeShift window as specified by `maxTimeShift` (which is a negative value) and 0. When the provided `offset` is
1987
+ * positive, it will be interpreted as a UNIX timestamp in seconds and converted to fit into the timeShift window.
1988
+ * When the provided `offset` is negative, but lower than `maxTimeShift`, then it will be clamped to `maxTimeShift`.
1989
+ * Has no effect for VoD.
1990
+ *
1991
+ * Has no effect if no sources are loaded.
1992
+ */
1993
+ timeShift: (offset: number) => void;
1962
1994
  /**
1963
1995
  * Mutes the player if an audio track is available. Has no effect if the player is already muted.
1964
1996
  */
@@ -2055,6 +2087,16 @@ declare class Player extends NativeInstance<PlayerConfig> {
2055
2087
  * @platform iOS, Android
2056
2088
  */
2057
2089
  isAd: () => Promise<boolean>;
2090
+ /**
2091
+ * The current time shift of the live stream in seconds. This value is always 0 if the active `source` is not a
2092
+ * live stream or no sources are loaded.
2093
+ */
2094
+ getTimeShift: () => Promise<number>;
2095
+ /**
2096
+ * The limit in seconds for time shifting. This value is either negative or 0 and it is always 0 if the active
2097
+ * `source` is not a live stream or no sources are loaded.
2098
+ */
2099
+ getMaxTimeShift: () => Promise<number>;
2058
2100
  }
2059
2101
 
2060
2102
  /**
@@ -2147,4 +2189,4 @@ declare function PlayerView({ style, player, fullscreenHandler, customMessageHan
2147
2189
  */
2148
2190
  declare function usePlayer(config?: PlayerConfig): Player;
2149
2191
 
2150
- export { Ad, AdBreak, AdBreakFinishedEvent, AdBreakStartedEvent, AdClickedEvent, AdConfig, AdData, AdErrorEvent, AdFinishedEvent, AdItem, AdManifestLoadEvent, AdManifestLoadedEvent, AdQuartile, AdQuartileEvent, AdScheduledEvent, AdSkippedEvent, AdSource, AdSourceType, AdStartedEvent, AdvertisingConfig, AnalyticsCollector, AnalyticsConfig, AudioAddedEvent, AudioChangedEvent, AudioRemovedEvent, AudioSession, AudioSessionCategory, BasePlayerViewProps, CdnProvider, CustomDataConfig, CustomMessageHandler, DestroyEvent, Drm, DrmConfig, ErrorEvent, Event, EventSource, FairplayConfig, FullscreenDisabledEvent, FullscreenEnabledEvent, FullscreenEnterEvent, FullscreenExitEvent, FullscreenHandler, LoadingState, MutedEvent, PausedEvent, PictureInPictureAvailabilityChangedEvent, PictureInPictureEnterEvent, PictureInPictureEnteredEvent, PictureInPictureExitEvent, PictureInPictureExitedEvent, PlayEvent, PlaybackConfig, PlaybackFinishedEvent, Player, PlayerActiveEvent, PlayerConfig, PlayerErrorEvent, PlayerView, PlayerViewProps, PlayerWarningEvent, PlayingEvent, ReadyEvent, ScalingMode, SeekEvent, SeekedEvent, SideLoadedSubtitleTrack, Source, SourceConfig, SourceErrorEvent, SourceLoadEvent, SourceLoadedEvent, SourceType, SourceUnloadedEvent, SourceWarningEvent, StallEndedEvent, StallStartedEvent, StyleConfig, SubtitleAddedEvent, SubtitleChangedEvent, SubtitleFormat, SubtitleRemovedEvent, SubtitleTrack, TimeChangedEvent, UnmutedEvent, VideoPlaybackQualityChangedEvent, WidevineConfig, usePlayer };
2192
+ export { Ad, AdBreak, AdBreakFinishedEvent, AdBreakStartedEvent, AdClickedEvent, AdConfig, AdData, AdErrorEvent, AdFinishedEvent, AdItem, AdManifestLoadEvent, AdManifestLoadedEvent, AdQuartile, AdQuartileEvent, AdScheduledEvent, AdSkippedEvent, AdSource, AdSourceType, AdStartedEvent, AdvertisingConfig, AnalyticsCollector, AnalyticsConfig, AudioAddedEvent, AudioChangedEvent, AudioRemovedEvent, AudioSession, AudioSessionCategory, BasePlayerViewProps, CdnProvider, CustomDataConfig, CustomMessageHandler, DestroyEvent, Drm, DrmConfig, ErrorEvent, Event, EventSource, FairplayConfig, FullscreenDisabledEvent, FullscreenEnabledEvent, FullscreenEnterEvent, FullscreenExitEvent, FullscreenHandler, LoadingState, MutedEvent, PausedEvent, PictureInPictureAvailabilityChangedEvent, PictureInPictureEnterEvent, PictureInPictureEnteredEvent, PictureInPictureExitEvent, PictureInPictureExitedEvent, PlayEvent, PlaybackConfig, PlaybackFinishedEvent, Player, PlayerActiveEvent, PlayerConfig, PlayerErrorEvent, PlayerView, PlayerViewProps, PlayerWarningEvent, PlayingEvent, ReadyEvent, ScalingMode, SeekEvent, SeekedEvent, SideLoadedSubtitleTrack, Source, SourceConfig, SourceErrorEvent, SourceLoadEvent, SourceLoadedEvent, SourceType, SourceUnloadedEvent, SourceWarningEvent, StallEndedEvent, StallStartedEvent, StyleConfig, SubtitleAddedEvent, SubtitleChangedEvent, SubtitleFormat, SubtitleRemovedEvent, SubtitleTrack, TimeChangedEvent, TimeShiftEvent, TimeShiftedEvent, UnmutedEvent, VideoPlaybackQualityChangedEvent, WidevineConfig, usePlayer };
package/lib/index.js CHANGED
@@ -361,6 +361,8 @@ function PlayerView({
361
361
  onReady: proxy(props.onReady),
362
362
  onSeek: proxy(props.onSeek),
363
363
  onSeeked: proxy(props.onSeeked),
364
+ onTimeShift: proxy(props.onTimeShift),
365
+ onTimeShifted: proxy(props.onTimeShifted),
364
366
  onStallStarted: proxy(props.onStallStarted),
365
367
  onStallEnded: proxy(props.onStallEnded),
366
368
  onSourceError: proxy(props.onSourceError),
@@ -573,6 +575,9 @@ var Player = class extends NativeInstance {
573
575
  __publicField(this, "seek", (time) => {
574
576
  PlayerModule.seek(this.nativeId, time);
575
577
  });
578
+ __publicField(this, "timeShift", (offset) => {
579
+ PlayerModule.timeShift(this.nativeId, offset);
580
+ });
576
581
  __publicField(this, "mute", () => {
577
582
  PlayerModule.mute(this.nativeId);
578
583
  });
@@ -639,9 +644,15 @@ var Player = class extends NativeInstance {
639
644
  __publicField(this, "skipAd", () => {
640
645
  PlayerModule.skipAd(this.nativeId);
641
646
  });
642
- __publicField(this, "isAd", () => {
647
+ __publicField(this, "isAd", async () => {
643
648
  return PlayerModule.isAd(this.nativeId);
644
649
  });
650
+ __publicField(this, "getTimeShift", async () => {
651
+ return PlayerModule.getTimeShift(this.nativeId);
652
+ });
653
+ __publicField(this, "getMaxTimeShift", async () => {
654
+ return PlayerModule.getMaxTimeShift(this.nativeId);
655
+ });
645
656
  }
646
657
  };
647
658
 
package/lib/index.mjs CHANGED
@@ -322,6 +322,8 @@ function PlayerView({
322
322
  onReady: proxy(props.onReady),
323
323
  onSeek: proxy(props.onSeek),
324
324
  onSeeked: proxy(props.onSeeked),
325
+ onTimeShift: proxy(props.onTimeShift),
326
+ onTimeShifted: proxy(props.onTimeShifted),
325
327
  onStallStarted: proxy(props.onStallStarted),
326
328
  onStallEnded: proxy(props.onStallEnded),
327
329
  onSourceError: proxy(props.onSourceError),
@@ -534,6 +536,9 @@ var Player = class extends NativeInstance {
534
536
  __publicField(this, "seek", (time) => {
535
537
  PlayerModule.seek(this.nativeId, time);
536
538
  });
539
+ __publicField(this, "timeShift", (offset) => {
540
+ PlayerModule.timeShift(this.nativeId, offset);
541
+ });
537
542
  __publicField(this, "mute", () => {
538
543
  PlayerModule.mute(this.nativeId);
539
544
  });
@@ -600,9 +605,15 @@ var Player = class extends NativeInstance {
600
605
  __publicField(this, "skipAd", () => {
601
606
  PlayerModule.skipAd(this.nativeId);
602
607
  });
603
- __publicField(this, "isAd", () => {
608
+ __publicField(this, "isAd", async () => {
604
609
  return PlayerModule.isAd(this.nativeId);
605
610
  });
611
+ __publicField(this, "getTimeShift", async () => {
612
+ return PlayerModule.getTimeShift(this.nativeId);
613
+ });
614
+ __publicField(this, "getMaxTimeShift", async () => {
615
+ return PlayerModule.getMaxTimeShift(this.nativeId);
616
+ });
606
617
  }
607
618
  };
608
619
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bitmovin-player-react-native",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
4
  "description": "Official React Native bindings for Bitmovin's mobile Player SDKs.",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/index.mjs",
@@ -54,6 +54,7 @@
54
54
  "@types/lodash.omit": "4.5.0",
55
55
  "@types/react": "18.0.15",
56
56
  "@types/react-native": "0.69.7",
57
+ "react-native": "0.69.7",
57
58
  "babel-plugin-module-resolver": "4.1.0",
58
59
  "commitlint": "17.1.2",
59
60
  "eslint": "8.24.0",
@@ -69,9 +70,7 @@
69
70
  "typescript": "4.8.4"
70
71
  },
71
72
  "dependencies": {
72
- "lodash.omit": "4.5.0",
73
- "react-native": "0.69.10",
74
- "react": "18.0.0"
73
+ "lodash.omit": "4.5.0"
75
74
  },
76
75
  "peerDependencies": {
77
76
  "react": ">=17",
@@ -33,6 +33,8 @@ import {
33
33
  ReadyEvent,
34
34
  SeekedEvent,
35
35
  SeekEvent,
36
+ TimeShiftEvent,
37
+ TimeShiftedEvent,
36
38
  StallStartedEvent,
37
39
  StallEndedEvent,
38
40
  SourceErrorEvent,
@@ -89,6 +91,8 @@ interface EventProps {
89
91
  onReady: ReadyEvent;
90
92
  onSeek: SeekEvent;
91
93
  onSeeked: SeekedEvent;
94
+ onTimeShift: TimeShiftEvent;
95
+ onTimeShifted: TimeShiftedEvent;
92
96
  onStallStarted: StallStartedEvent;
93
97
  onStallEnded: StallEndedEvent;
94
98
  onSourceError: SourceErrorEvent;
@@ -176,6 +176,8 @@ export function PlayerView({
176
176
  onReady={proxy(props.onReady)}
177
177
  onSeek={proxy(props.onSeek)}
178
178
  onSeeked={proxy(props.onSeeked)}
179
+ onTimeShift={proxy(props.onTimeShift)}
180
+ onTimeShifted={proxy(props.onTimeShifted)}
179
181
  onStallStarted={proxy(props.onStallStarted)}
180
182
  onStallEnded={proxy(props.onStallEnded)}
181
183
  onSourceError={proxy(props.onSourceError)}
package/src/events.ts CHANGED
@@ -168,6 +168,27 @@ export interface SeekEvent extends Event {
168
168
  */
169
169
  export interface SeekedEvent extends Event {}
170
170
 
171
+ /**
172
+ * Emitted when the player starts time shifting.
173
+ * Only applies to live streams.
174
+ */
175
+ export interface TimeShiftEvent extends Event {
176
+ /**
177
+ * The position from which we start the time shift
178
+ */
179
+ position: number;
180
+ /**
181
+ * The position to which we want to jump for the time shift
182
+ */
183
+ targetPosition: number;
184
+ }
185
+
186
+ /**
187
+ * Emitted when time shifting has finished and data is available to continue playback.
188
+ * Only applies to live streams.
189
+ */
190
+ export interface TimeShiftedEvent extends Event {}
191
+
171
192
  /**
172
193
  * Emitted when the player begins to stall and to buffer due to an empty buffer.
173
194
  */
package/src/player.ts CHANGED
@@ -235,6 +235,19 @@ export class Player extends NativeInstance<PlayerConfig> {
235
235
  PlayerModule.seek(this.nativeId, time);
236
236
  };
237
237
 
238
+ /**
239
+ * Shifts the time to the given `offset` in seconds from the live edge. The resulting offset has to be within the
240
+ * timeShift window as specified by `maxTimeShift` (which is a negative value) and 0. When the provided `offset` is
241
+ * positive, it will be interpreted as a UNIX timestamp in seconds and converted to fit into the timeShift window.
242
+ * When the provided `offset` is negative, but lower than `maxTimeShift`, then it will be clamped to `maxTimeShift`.
243
+ * Has no effect for VoD.
244
+ *
245
+ * Has no effect if no sources are loaded.
246
+ */
247
+ timeShift = (offset: number) => {
248
+ PlayerModule.timeShift(this.nativeId, offset);
249
+ };
250
+
238
251
  /**
239
252
  * Mutes the player if an audio track is available. Has no effect if the player is already muted.
240
253
  */
@@ -396,7 +409,23 @@ export class Player extends NativeInstance<PlayerConfig> {
396
409
  * @returns `true` while an ad is being played back or when main content playback has been paused for ad playback.
397
410
  * @platform iOS, Android
398
411
  */
399
- isAd = (): Promise<boolean> => {
412
+ isAd = async (): Promise<boolean> => {
400
413
  return PlayerModule.isAd(this.nativeId);
401
414
  };
415
+
416
+ /**
417
+ * The current time shift of the live stream in seconds. This value is always 0 if the active `source` is not a
418
+ * live stream or no sources are loaded.
419
+ */
420
+ getTimeShift = async (): Promise<number> => {
421
+ return PlayerModule.getTimeShift(this.nativeId);
422
+ };
423
+
424
+ /**
425
+ * The limit in seconds for time shifting. This value is either negative or 0 and it is always 0 if the active
426
+ * `source` is not a live stream or no sources are loaded.
427
+ */
428
+ getMaxTimeShift = async (): Promise<number> => {
429
+ return PlayerModule.getMaxTimeShift(this.nativeId);
430
+ };
402
431
  }