fix(android): implement live configuration management (#3792)
* perf: ensure we do not provide callback to native if no callback provided from app * chore: rework bufferConfig to make it more generic and reduce ReactExoplayerView code size * chore: improve issue template * fix(android): avoid video view flickering at playback startup * feat(android): implement live buffer configuration * chore: fix linter
This commit is contained in:
parent
8fdc52372c
commit
e16730de11
@ -1,6 +1,7 @@
|
|||||||
package com.brentvatne.common.api
|
package com.brentvatne.common.api
|
||||||
|
|
||||||
import com.brentvatne.common.toolbox.ReactBridgeUtils.safeGetDouble
|
import com.brentvatne.common.toolbox.ReactBridgeUtils.safeGetDouble
|
||||||
|
import com.brentvatne.common.toolbox.ReactBridgeUtils.safeGetFloat
|
||||||
import com.brentvatne.common.toolbox.ReactBridgeUtils.safeGetInt
|
import com.brentvatne.common.toolbox.ReactBridgeUtils.safeGetInt
|
||||||
import com.facebook.react.bridge.ReadableMap
|
import com.facebook.react.bridge.ReadableMap
|
||||||
|
|
||||||
@ -20,6 +21,35 @@ class BufferConfig {
|
|||||||
var minBackBufferMemoryReservePercent = BufferConfigPropUnsetDouble
|
var minBackBufferMemoryReservePercent = BufferConfigPropUnsetDouble
|
||||||
var minBufferMemoryReservePercent = BufferConfigPropUnsetDouble
|
var minBufferMemoryReservePercent = BufferConfigPropUnsetDouble
|
||||||
|
|
||||||
|
var live: Live = Live()
|
||||||
|
|
||||||
|
class Live {
|
||||||
|
var maxPlaybackSpeed: Float = BufferConfigPropUnsetDouble.toFloat()
|
||||||
|
var minPlaybackSpeed: Float = BufferConfigPropUnsetDouble.toFloat()
|
||||||
|
var maxOffsetMs: Long = BufferConfigPropUnsetInt.toLong()
|
||||||
|
var minOffsetMs: Long = BufferConfigPropUnsetInt.toLong()
|
||||||
|
var targetOffsetMs: Long = BufferConfigPropUnsetInt.toLong()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val PROP_BUFFER_CONFIG_LIVE_MAX_PLAYBACK_SPEED = "maxPlaybackSpeed"
|
||||||
|
private val PROP_BUFFER_CONFIG_LIVE_MIN_PLAYBACK_SPEED = "minPlaybackSpeed"
|
||||||
|
private val PROP_BUFFER_CONFIG_LIVE_MAX_OFFSET_MS = "maxOffsetMs"
|
||||||
|
private val PROP_BUFFER_CONFIG_LIVE_MIN_OFFSET_MS = "minOffsetMs"
|
||||||
|
private val PROP_BUFFER_CONFIG_LIVE_TARGET_OFFSET_MS = "targetOffsetMs"
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parse(src: ReadableMap?): Live {
|
||||||
|
val live = Live()
|
||||||
|
live.maxPlaybackSpeed = safeGetFloat(src, PROP_BUFFER_CONFIG_LIVE_MAX_PLAYBACK_SPEED, BufferConfigPropUnsetDouble.toFloat())
|
||||||
|
live.minPlaybackSpeed = safeGetFloat(src, PROP_BUFFER_CONFIG_LIVE_MIN_PLAYBACK_SPEED, BufferConfigPropUnsetDouble.toFloat())
|
||||||
|
live.maxOffsetMs = safeGetInt(src, PROP_BUFFER_CONFIG_LIVE_MAX_OFFSET_MS, BufferConfigPropUnsetInt).toLong()
|
||||||
|
live.minOffsetMs = safeGetInt(src, PROP_BUFFER_CONFIG_LIVE_MIN_OFFSET_MS, BufferConfigPropUnsetInt).toLong()
|
||||||
|
live.targetOffsetMs = safeGetInt(src, PROP_BUFFER_CONFIG_LIVE_TARGET_OFFSET_MS, BufferConfigPropUnsetInt).toLong()
|
||||||
|
return live
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val BufferConfigPropUnsetInt = -1
|
val BufferConfigPropUnsetInt = -1
|
||||||
val BufferConfigPropUnsetDouble = -1.0
|
val BufferConfigPropUnsetDouble = -1.0
|
||||||
@ -33,6 +63,7 @@ class BufferConfig {
|
|||||||
private val PROP_BUFFER_CONFIG_MIN_BACK_BUFFER_MEMORY_RESERVE_PERCENT = "minBackBufferMemoryReservePercent"
|
private val PROP_BUFFER_CONFIG_MIN_BACK_BUFFER_MEMORY_RESERVE_PERCENT = "minBackBufferMemoryReservePercent"
|
||||||
private val PROP_BUFFER_CONFIG_MIN_BUFFER_MEMORY_RESERVE_PERCENT = "minBufferMemoryReservePercent"
|
private val PROP_BUFFER_CONFIG_MIN_BUFFER_MEMORY_RESERVE_PERCENT = "minBufferMemoryReservePercent"
|
||||||
private val PROP_BUFFER_CONFIG_BACK_BUFFER_DURATION_MS = "backBufferDurationMs"
|
private val PROP_BUFFER_CONFIG_BACK_BUFFER_DURATION_MS = "backBufferDurationMs"
|
||||||
|
private val PROP_BUFFER_CONFIG_LIVE = "live"
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun parse(src: ReadableMap?): BufferConfig {
|
fun parse(src: ReadableMap?): BufferConfig {
|
||||||
@ -59,6 +90,7 @@ class BufferConfig {
|
|||||||
BufferConfigPropUnsetDouble
|
BufferConfigPropUnsetDouble
|
||||||
)
|
)
|
||||||
bufferConfig.backBufferDurationMs = safeGetInt(src, PROP_BUFFER_CONFIG_BACK_BUFFER_DURATION_MS, BufferConfigPropUnsetInt)
|
bufferConfig.backBufferDurationMs = safeGetInt(src, PROP_BUFFER_CONFIG_BACK_BUFFER_DURATION_MS, BufferConfigPropUnsetInt)
|
||||||
|
bufferConfig.live = Live.parse(src.getMap(PROP_BUFFER_CONFIG_LIVE))
|
||||||
}
|
}
|
||||||
return bufferConfig
|
return bufferConfig
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
package com.brentvatne.exoplayer
|
||||||
|
|
||||||
|
import androidx.media3.common.MediaItem.LiveConfiguration
|
||||||
|
import com.brentvatne.common.api.BufferConfig
|
||||||
|
import com.brentvatne.common.api.BufferConfig.Live
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper functions to create exoplayer configuration
|
||||||
|
*/
|
||||||
|
object ConfigurationUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a media3.LiveConfiguration.Builder from parsed BufferConfig
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun getLiveConfiguration(bufferConfig: BufferConfig): LiveConfiguration.Builder {
|
||||||
|
val liveConfiguration = LiveConfiguration.Builder()
|
||||||
|
val live: Live = bufferConfig.live
|
||||||
|
if (bufferConfig.live.maxOffsetMs >= 0) {
|
||||||
|
liveConfiguration.setMaxOffsetMs(live.maxOffsetMs)
|
||||||
|
}
|
||||||
|
if (bufferConfig.live.maxPlaybackSpeed >= 0) {
|
||||||
|
liveConfiguration.setMaxPlaybackSpeed(live.maxPlaybackSpeed)
|
||||||
|
}
|
||||||
|
if (bufferConfig.live.targetOffsetMs >= 0) {
|
||||||
|
liveConfiguration.setTargetOffsetMs(live.targetOffsetMs)
|
||||||
|
}
|
||||||
|
if (bufferConfig.live.minOffsetMs >= 0) {
|
||||||
|
liveConfiguration.setMinOffsetMs(live.minOffsetMs)
|
||||||
|
}
|
||||||
|
if (bufferConfig.live.minPlaybackSpeed >= 0) {
|
||||||
|
liveConfiguration.setMinPlaybackSpeed(live.minPlaybackSpeed)
|
||||||
|
}
|
||||||
|
return liveConfiguration
|
||||||
|
}
|
||||||
|
}
|
@ -965,6 +965,9 @@ public class ReactExoplayerView extends FrameLayout implements
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MediaItem.LiveConfiguration.Builder liveConfiguration = ConfigurationUtils.getLiveConfiguration(bufferConfig);
|
||||||
|
mediaItemBuilder.setLiveConfiguration(liveConfiguration.build());
|
||||||
|
|
||||||
MediaSource.Factory mediaSourceFactory;
|
MediaSource.Factory mediaSourceFactory;
|
||||||
DrmSessionManagerProvider drmProvider;
|
DrmSessionManagerProvider drmProvider;
|
||||||
List<StreamKey> streamKeys = new ArrayList();
|
List<StreamKey> streamKeys = new ArrayList();
|
||||||
|
@ -83,6 +83,20 @@ Adjust the buffer settings. This prop takes an object with one or more of the pr
|
|||||||
| minBackBufferMemoryReservePercent | number | The percentage of available app memory at which during startup the back buffer will be disabled, between 0 and 1 |
|
| minBackBufferMemoryReservePercent | number | The percentage of available app memory at which during startup the back buffer will be disabled, between 0 and 1 |
|
||||||
| minBufferMemoryReservePercent | number | The percentage of available app memory to keep in reserve that prevents buffer from using it, between 0 and 1 |
|
| minBufferMemoryReservePercent | number | The percentage of available app memory to keep in reserve that prevents buffer from using it, between 0 and 1 |
|
||||||
| cacheSizeMB | number | Cache size in MB, enabling this to prevent new src requests and save bandwidth while repeating videos, or 0 to disable. Android only. |
|
| cacheSizeMB | number | Cache size in MB, enabling this to prevent new src requests and save bandwidth while repeating videos, or 0 to disable. Android only. |
|
||||||
|
| live | object | Object containing another config set for live playback configuration, see next table |
|
||||||
|
|
||||||
|
|
||||||
|
Description of live object:
|
||||||
|
|
||||||
|
| Property | Type | Description |
|
||||||
|
| --------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|
| maxPlaybackSpeed | number | The maximum playback speed the player can use to catch up when trying to reach the target live offset. |
|
||||||
|
| minPlaybackSpeed | number | The minimum playback speed the player can use to fall back when trying to reach the target live offset. |
|
||||||
|
| maxOffsetMs | number | The maximum allowed live offset. Even when adjusting the offset to current network conditions, the player will not attempt to get above this offset during playback. |
|
||||||
|
| minOffsetMs | number | The minimum allowed live offset. Even when adjusting the offset to current network conditions, the player will not attempt to get below this offset during playback. |
|
||||||
|
| targetOffsetMs | number | The target live offset. The player will attempt to get close to this live offset during playback if possible. |
|
||||||
|
|
||||||
|
For android, more informations about live configuration can be find [here](https://developer.android.com/media/media3/exoplayer/live-streaming?hl=en)
|
||||||
|
|
||||||
Example with default values:
|
Example with default values:
|
||||||
|
|
||||||
@ -93,7 +107,10 @@ bufferConfig={{
|
|||||||
bufferForPlaybackMs: 2500,
|
bufferForPlaybackMs: 2500,
|
||||||
bufferForPlaybackAfterRebufferMs: 5000,
|
bufferForPlaybackAfterRebufferMs: 5000,
|
||||||
backBufferDurationMs: 120000,
|
backBufferDurationMs: 120000,
|
||||||
cacheSizeMB: 0
|
cacheSizeMB: 0,
|
||||||
|
live: {
|
||||||
|
targetOffsetMs: 500,
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -930,6 +930,9 @@ class VideoPlayer extends Component {
|
|||||||
bufferForPlaybackMs: 2500,
|
bufferForPlaybackMs: 2500,
|
||||||
bufferForPlaybackAfterRebufferMs: 5000,
|
bufferForPlaybackAfterRebufferMs: 5000,
|
||||||
cacheSizeMB: this.state.useCache ? 200 : 0,
|
cacheSizeMB: this.state.useCache ? 200 : 0,
|
||||||
|
live: {
|
||||||
|
targetOffsetMs: 500,
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
preventsDisplaySleepDuringVideoPlayback={true}
|
preventsDisplaySleepDuringVideoPlayback={true}
|
||||||
poster={this.state.poster}
|
poster={this.state.poster}
|
||||||
|
@ -93,6 +93,14 @@ export type Seek = Readonly<{
|
|||||||
tolerance?: Float;
|
tolerance?: Float;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
type BufferConfigLive = Readonly<{
|
||||||
|
maxPlaybackSpeed?: Float;
|
||||||
|
minPlaybackSpeed?: Float;
|
||||||
|
maxOffsetMs?: Int32;
|
||||||
|
minOffsetMs?: Int32;
|
||||||
|
targetOffsetMs?: Int32;
|
||||||
|
}>;
|
||||||
|
|
||||||
type BufferingStrategyType = WithDefault<string, 'Default'>;
|
type BufferingStrategyType = WithDefault<string, 'Default'>;
|
||||||
|
|
||||||
type BufferConfig = Readonly<{
|
type BufferConfig = Readonly<{
|
||||||
@ -105,6 +113,7 @@ type BufferConfig = Readonly<{
|
|||||||
minBackBufferMemoryReservePercent?: Float;
|
minBackBufferMemoryReservePercent?: Float;
|
||||||
minBufferMemoryReservePercent?: Float;
|
minBufferMemoryReservePercent?: Float;
|
||||||
cacheSizeMB?: Float;
|
cacheSizeMB?: Float;
|
||||||
|
live?: BufferConfigLive;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
type SubtitleStyle = Readonly<{
|
type SubtitleStyle = Readonly<{
|
||||||
|
@ -74,6 +74,14 @@ export enum BufferingStrategyType {
|
|||||||
DEPENDING_ON_MEMORY = 'DependingOnMemory',
|
DEPENDING_ON_MEMORY = 'DependingOnMemory',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type BufferConfigLive = {
|
||||||
|
maxPlaybackSpeed?: number;
|
||||||
|
minPlaybackSpeed?: number;
|
||||||
|
maxOffsetMs?: number;
|
||||||
|
minOffsetMs?: number;
|
||||||
|
targetOffsetMs?: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type BufferConfig = {
|
export type BufferConfig = {
|
||||||
minBufferMs?: number;
|
minBufferMs?: number;
|
||||||
maxBufferMs?: number;
|
maxBufferMs?: number;
|
||||||
@ -84,6 +92,7 @@ export type BufferConfig = {
|
|||||||
minBackBufferMemoryReservePercent?: number;
|
minBackBufferMemoryReservePercent?: number;
|
||||||
minBufferMemoryReservePercent?: number;
|
minBufferMemoryReservePercent?: number;
|
||||||
cacheSizeMB?: number;
|
cacheSizeMB?: number;
|
||||||
|
live?: BufferConfigLive;
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum SelectedTrackType {
|
export enum SelectedTrackType {
|
||||||
|
Loading…
Reference in New Issue
Block a user