Skip to content

Commit

Permalink
feat: onPipChange (#155)
Browse files Browse the repository at this point in the history
merging this to get included in next release
  • Loading branch information
Bowlerr authored Feb 6, 2024
1 parent 367096f commit 1db41ee
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,18 @@ class AmazonIvsView(private val context: ThemedReactContext) : FrameLayout(conte
private var lastLiveLatency: Long? = null
private var lastBitrate: Long? = null
private var lastDuration: Long? = null
private var lastPipState: Boolean = false;
private var finishedLoading: Boolean = false
private var pipEnabled: Boolean = false
private var isInBackground: Boolean = false


enum class Events(private val mName: String) {
STATE_CHANGED("onPlayerStateChange"),
DURATION_CHANGED("onDurationChange"),
ERROR("onError"),
QUALITY_CHANGED("onQualityChange"),
PIP_CHANGED("onPipChange"),
CUE("onTextCue"),
METADATA_CUE("onTextMetadataCue"),
LOAD("onLoad"),
Expand Down Expand Up @@ -281,6 +284,14 @@ class AmazonIvsView(private val context: ThemedReactContext) : FrameLayout(conte
reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(id, Events.PROGRESS.toString(), data)
}

fun onPipChange(active: Boolean) {
val reactContext = context as ReactContext
val data = Arguments.createMap()
data.putString("active", if (active) "true" else "false")

reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(id, Events.PIP_CHANGED.toString(), data)
}

private fun convertMilliSecondsToSeconds (milliSeconds: Long): Double {
return milliSeconds / 1000.0
}
Expand Down Expand Up @@ -380,6 +391,17 @@ class AmazonIvsView(private val context: ThemedReactContext) : FrameLayout(conte
private fun intervalHandler() {
val reactContext = context as ReactContext

if (pipEnabled)
{
val activity: Activity? = reactContext.currentActivity
val isPipActive = activity!!.isInPictureInPictureMode
if(lastPipState !== isPipActive)
{
lastPipState = isPipActive
onPipChange(isPipActive === true)
}
}

if (lastLiveLatency != player?.liveLatency) {
val liveLatencyData = Arguments.createMap()

Expand Down
8 changes: 8 additions & 0 deletions docs/ivs-player-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,14 @@ Callback that returns new quality that is used in video/stream playback.

type: [`(quality: Quality) => void`](./types.md#Quality)

### onPipChange _(optional)_

Callback that returns changes to the picture in picture state.
This returns false if no picture in picture is active. It returns true if picture in picture is active.
Available only for Android N+ and iOS 15+

type: `(isActive: boolean) => void`

### resizeMode _(optional)_

Defines different modes for displaying video in a Player.
Expand Down
3 changes: 3 additions & 0 deletions docs/usage-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ You can find the full list of events in the [api-reference](./ivs-player-referen
onQualityChange={(newQuality) => {
console.log(`quality changed: ${newQuality?.name}`)
}}
onPipChange={(isActive) => {
console.log(`picture in picture changed - isActive: ${isActive}`)
}}
onRebuffering={() => {
console.log('rebuffering...')
}}
Expand Down
3 changes: 3 additions & 0 deletions example/src/screens/PlaygroundExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,9 @@ export default function PlaygroundExample() {
setDetectedQuality(newQuality);
log(`quality changed: ${newQuality?.name}`);
}}
onPipChange={(isActive) => {
log(`picture in picture changed - isActive: ${isActive}`);
}}
onRebuffering={() => setBuffering(true)}
onLoadStart={() => log(`load started`)}
onLoad={(loadedDuration) =>
Expand Down
1 change: 1 addition & 0 deletions ios/AmazonIvsManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ @interface RCT_EXTERN_MODULE(AmazonIvsManager, RCTViewManager)
RCT_EXPORT_VIEW_PROPERTY(onPlayerStateChange, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onDurationChange, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onQualityChange, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onPipChange, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onRebuffering, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onLoadStart, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onLoad, RCTDirectEventBlock)
Expand Down
16 changes: 16 additions & 0 deletions ios/AmazonIvsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class AmazonIvsView: UIView, IVSPlayer.Delegate {
@objc var onPlayerStateChange: RCTDirectEventBlock?
@objc var onDurationChange: RCTDirectEventBlock?
@objc var onQualityChange: RCTDirectEventBlock?
@objc var onPipChange: RCTDirectEventBlock?
@objc var onRebuffering: RCTDirectEventBlock?
@objc var onLoadStart: RCTDirectEventBlock?
@objc var onLoad: RCTDirectEventBlock?
Expand Down Expand Up @@ -37,6 +38,8 @@ class AmazonIvsView: UIView, IVSPlayer.Delegate {


private var _pipController: Any? = nil
private var isPipActive: Bool = false


@available(iOS 15, *)
private var pipController: AVPictureInPictureController? {
Expand Down Expand Up @@ -498,3 +501,16 @@ class AmazonIvsView: UIView, IVSPlayer.Delegate {

}
}
@available(iOS 15, *)
extension AmazonIvsView: AVPictureInPictureControllerDelegate {
func pictureInPictureControllerDidStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
isPipActive = true
onPipChange?(["active": isPipActive])
}

func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
isPipActive = false
onPipChange?(["active": isPipActive])
}
}

1 change: 1 addition & 0 deletions src/IVSPlayer.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ declare type Props = {|
onPlayerStateChange?: (state: number) => void,
onDurationChange?: (duration: number | null) => void,
onQualityChange?: (quality: Quality | null) => void,
onPipChange?: (isActive: boolean) => void,
onRebuffering?: () => void,
onLoadStart?: () => void,
onLoad?: (duration: number | null) => void,
Expand Down
11 changes: 11 additions & 0 deletions src/IVSPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ type IVSPlayerProps = {
event: NativeSyntheticEvent<{ duration: number | null }>
): void;
onQualityChange?(event: NativeSyntheticEvent<{ quality: Quality }>): void;
onPipChange?(event: NativeSyntheticEvent<{ active: boolean | string }>): void;
onRebuffering?(): void;
onLoadStart?(): void;
onLoad?(event: NativeSyntheticEvent<{ duration: number | null }>): void;
Expand Down Expand Up @@ -105,6 +106,7 @@ export type Props = {
onPlayerStateChange?(state: PlayerState): void;
onDurationChange?(duration: number | null): void;
onQualityChange?(quality: Quality | null): void;
onPipChange?(isActive: boolean): void;
onRebuffering?(): void;
onLoadStart?(): void;
onLoad?(duration: number | null): void;
Expand Down Expand Up @@ -153,6 +155,7 @@ const IVSPlayerContainer = React.forwardRef<IVSPlayerRef, Props>(
onPlayerStateChange,
onDurationChange,
onQualityChange,
onPipChange,
onRebuffering,
onLoadStart,
onLoad,
Expand Down Expand Up @@ -264,6 +267,13 @@ const IVSPlayerContainer = React.forwardRef<IVSPlayerRef, Props>(
onQualityChange?.(newQuality);
};

const onPipChangeHandler = (
event: NativeSyntheticEvent<{ active: string | boolean }>
) => {
const { active } = event.nativeEvent;
onPipChange?.(active === true || active === 'true');
};

const onLoadHandler = (
event: NativeSyntheticEvent<{
duration: number | null;
Expand Down Expand Up @@ -366,6 +376,7 @@ const IVSPlayerContainer = React.forwardRef<IVSPlayerRef, Props>(
onData={onDataHandler}
onSeek={onSeekHandler}
onQualityChange={onQualityChangeHandler}
onPipChange={onPipChangeHandler}
onPlayerStateChange={onPlayerStateChangeHandler}
onDurationChange={onDurationChangeHandler}
onRebuffering={onRebuffering}
Expand Down
8 changes: 8 additions & 0 deletions src/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ test('Passing onQualityChange down works correctly', async () => {
);
});

test('Passing onPipChange down works correctly with boolean', async () => {
await testCallbackPassing('onPipChange', { active: true }, true);
});

test('Passing onPipChange down works correctly with string', async () => {
await testCallbackPassing('onPipChange', { active: 'true' }, true);
});

test('Passing onRebuffering down works correctly', async () => {
await testCallbackPassing('onRebuffering');
});
Expand Down

0 comments on commit 1db41ee

Please sign in to comment.