Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
This package implements native binding for Amazon IVS Player for iOS and Android Mobile Only.
| Android Mobile | iOS | Android TV | tvOS |
| :-----: | :-: | :---: | :-: |
| SDK >= 21 | >= 13 | **X** | **X** |
| SDK >= 24 | >= 15.1 | **X** | **X** |

## Installation

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,13 @@ class AmazonIvsView(private val context: ThemedReactContext) : FrameLayout(conte
LOAD_START("onLoadStart"),
REBUFFERING("onRebuffering"),
SEEK("onSeek"),
SEEK_COMPLETE("onSeekComplete"),
DATA("onData"),
LIVE_LATENCY_CHANGED("onLiveLatencyChange"),
VIDEO_STATISTICS("onVideoStatistics"),
PROGRESS("onProgress"),
TIME_POINT("onTimePoint");
TIME_POINT("onTimePoint"),
VIDEO_SIZE_CHANGE("onVideoSizeChange");

override fun toString(): String {
return mName
Expand Down Expand Up @@ -125,13 +127,16 @@ class AmazonIvsView(private val context: ThemedReactContext) : FrameLayout(conte

override fun onSeekCompleted(position: Long) {
onSeek(position)
onSeekComplete(true)
}

override fun onQualityChanged(quality: Quality) {
onQualityChange(quality)
}

override fun onVideoSizeChanged(p0: Int, p1: Int) {
onVideoSizeChange(p0, p1)

post(mLayoutRunnable)
}

Expand Down Expand Up @@ -302,9 +307,13 @@ class AmazonIvsView(private val context: ThemedReactContext) : FrameLayout(conte
}

fun setQuality(quality: ReadableMap?) {
if (quality != null) {
findQuality(quality)?.let {
player?.quality = it
if (quality == null) return
val target = if (quality.hasKey("target")) quality.getMap("target") else null
val isAdaptive = if (quality.hasKey("adaptive")) quality.getBoolean("adaptive") else true

if (target != null) {
findQuality(target)?.let { selectedQuality->
player?.setQuality(selectedQuality, isAdaptive)
}
}
}
Expand Down Expand Up @@ -610,6 +619,40 @@ class AmazonIvsView(private val context: ThemedReactContext) : FrameLayout(conte
)
}

fun onVideoSizeChange(p0: Int, p1: Int) {
val reactContext = context as ReactContext
val size = Arguments.createMap()
size.putInt("height", p0)
size.putInt("width", p1)

val data = Arguments.createMap()
data.putMap("size", size)

eventDispatcher.dispatchEvent(
IVSEvent(
getSurfaceId(reactContext),
id,
Events.VIDEO_SIZE_CHANGE,
data
)
)
}

fun onSeekComplete(success: Boolean) {
val reactContext = context as ReactContext
val data = Arguments.createMap()
data.putBoolean("success", success)

eventDispatcher.dispatchEvent(
IVSEvent(
getSurfaceId(reactContext),
id,
Events.SEEK_COMPLETE,
data
)
)
}

fun onPlayerRebuffering() {
val reactContext = context as ReactContext

Expand Down Expand Up @@ -784,6 +827,19 @@ class AmazonIvsView(private val context: ThemedReactContext) : FrameLayout(conte
}, 0, updatedProgressInterval)
}

fun setMaxVideoSize(maxSize: ReadableMap?) {
val width = maxSize?.getInt("width")
val height = maxSize?.getInt("height")

if (width != null && height != null) {
player?.setAutoMaxVideoSize(width, height)
}
}

fun setNetworkRecoveryMode(mode: String?) {
player?.setNetworkRecoveryMode(findNetworkRecoveryMode((mode)))
}

override fun onHostResume() {
isInBackground = false
stopBackgroundService()
Expand Down Expand Up @@ -867,4 +923,12 @@ class AmazonIvsView(private val context: ThemedReactContext) : FrameLayout(conte
}
}

private fun findNetworkRecoveryMode(mode: String?): Player.NetworkRecoveryMode {
return when (mode) {
"none" -> Player.NetworkRecoveryMode.NONE
"resume" -> Player.NetworkRecoveryMode.RESUME
else -> Player.NetworkRecoveryMode.NONE
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,20 @@ class AmazonIvsViewManager : SimpleViewManager<AmazonIvsView>(),
view?.setProgressInterval(value)
}

override fun setMaxVideoSize(
view: AmazonIvsView?,
value: ReadableMap?
) {
view?.setMaxVideoSize(value)
}

override fun setNetworkRecoveryMode(
view: AmazonIvsView?,
value: String?
) {
view?.setNetworkRecoveryMode(value)
}

override fun setPlayInBackground(
view: AmazonIvsView?,
value: Boolean
Expand Down
6 changes: 6 additions & 0 deletions docs/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ export type TextMetadataCue = {
export type ResizeMode = 'aspectFill' | 'aspectFit' | 'aspectZoom';
```

## NetworkRecoveryMode

```ts
export type NetworkRecoveryMode = 'none' | 'resume';
```

## Source

```ts
Expand Down
43 changes: 42 additions & 1 deletion docs/usage-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ You can also set the video volume or its quality using component props. The whol

In order to set video quality, you need to get the list of available qualities that come from the `onData` callback.

Optional `adaptive` flag:

- `adaptive: false`: Hard-locks the player to the specific resolution. It disables auto-quality (ABR). Use this when a user explicitly selects a resolution (e.g., "1080p").

- `adaptive: true`: Switches to the target resolution immediately but keeps auto-quality (ABR) enabled. The player may switch away from this resolution later if network conditions change.


```tsx
import IVSPlayer, { Quality } from 'amazon-ivs-react-native';

Expand All @@ -56,7 +63,31 @@ export default function App() {
<IVSPlayer
streamUrl="https://fcc3ddae59ed.us-west-2.playback.live-video.net/api/video/v1/us-west-2.893648527354.channel.DmumNckWFTqz.m3u8"
onData={(data) => setQualities(data.qualities)}
quality={qualities[0]}
quality={{
target: qualities[0],
adaptive: true // Optional: defaults to true. Set to false to force manual mode.
}}
/>
);
}
```

## LIMITING MAXIMUM VIDEO SIZE

You can limit the maximum video resolution chosen by the auto-quality algorithm using the `maxVideoSize` prop. This is useful for saving bandwidth or restricting quality on specific devices.

```tsx
import IVSPlayer, { Quality } from 'amazon-ivs-react-native';

export default function App() {
const [qualities, setQualities] = useState<Quality[]>();

return (
<IVSPlayer
streamUrl="https://fcc3ddae59ed.us-west-2.playback.live-video.net/api/video/v1/us-west-2.893648527354.channel.DmumNckWFTqz.m3u8"
maxVideoSize={{
size: { width: 1280, height: 720 },
}}
/>
);
}
Expand Down Expand Up @@ -129,6 +160,10 @@ You can find the full list of events in the [api-reference](./ivs-player-referen
onTimePoint={(timePoint) => {
console.log('time point', timePoint)
}}
onVideoSizeChange={(videoSize) => {
console.log('video width', videoSize.size.width)
console.log('video height', videoSize.size.height)
}}
/>
```

Expand All @@ -153,7 +188,13 @@ export default function App() {
};

const handleSeekToPress = () => {
// Basic usage
mediaPlayerRef?.current?.seekTo(15);

// OR usage with completion callback
mediaPlayerRef?.current?.seekTo(15, (success) => {
console.log('Seek finished, success:', success);
});
};

const handleTogglePipToPress = () => {
Expand Down
4 changes: 3 additions & 1 deletion example/src/screens/PlaygroundExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,9 @@ export default function PlaygroundExample() {
progressInterval={progressInterval}
volume={volume}
autoQualityMode={autoQualityMode}
quality={manualQuality}
quality={{
target: manualQuality,
}}
autoMaxQuality={autoMaxQuality}
breakpoints={breakpoints}
onSeek={(newPosition) => console.log('new position', newPosition)}
Expand Down
Loading
Loading