mirror of
https://github.com/zoriya/react-native-omni.git
synced 2026-08-12 00:49:32 +00:00
Handle rendition selection
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
package dev.zoriya.omni
|
||||
|
||||
import android.os.SystemClock
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.media3.common.C
|
||||
import androidx.media3.common.C.TRACK_TYPE_AUDIO
|
||||
import androidx.media3.common.C.TRACK_TYPE_TEXT
|
||||
@@ -16,6 +16,7 @@ import androidx.media3.common.Player.STATE_ENDED
|
||||
import androidx.media3.common.Player.STATE_IDLE
|
||||
import androidx.media3.common.Player.STATE_READY
|
||||
import androidx.media3.common.Tracks
|
||||
import androidx.media3.common.VideoSize
|
||||
import com.margelo.nitro.omni.BoolProperty
|
||||
import com.margelo.nitro.omni.HybridOmniEventMapSpec
|
||||
import com.margelo.nitro.omni.NumberProperty
|
||||
@@ -23,6 +24,7 @@ import com.margelo.nitro.omni.PlayerStatus
|
||||
import com.margelo.nitro.omni.Rendition
|
||||
import com.margelo.nitro.omni.Track
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
class EventMap(private val player: Player) : HybridOmniEventMapSpec(), Player.Listener {
|
||||
private val onPrevListeners = mutableSetOf<() -> Unit>()
|
||||
private val onNextListeners = mutableSetOf<() -> Unit>()
|
||||
@@ -36,8 +38,10 @@ class EventMap(private val player: Player) : HybridOmniEventMapSpec(), Player.Li
|
||||
private val stateListeners = mutableMapOf<NumberProperty, MutableSet<(Double) -> Unit>>()
|
||||
private val stateBoolListeners = mutableMapOf<BoolProperty, MutableSet<(Boolean) -> Unit>>()
|
||||
private val playerStatusListeners = mutableSetOf<(PlayerStatus) -> Unit>()
|
||||
private var lastTimePosDispatchMs = 0L
|
||||
|
||||
private var lastMediaItemIndex = 0
|
||||
private var lastRendition: Rendition? = null
|
||||
private var lastIsAutoQuality: Boolean? = null
|
||||
|
||||
init {
|
||||
player.addListener(this)
|
||||
@@ -61,6 +65,53 @@ class EventMap(private val player: Player) : HybridOmniEventMapSpec(), Player.Li
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getCurrentRendition(): Rendition? {
|
||||
val group = player.currentTracks.groups.firstOrNull {
|
||||
it.isSelected && it.type == TRACK_TYPE_VIDEO
|
||||
} ?: return null
|
||||
|
||||
val isAuto = player.trackSelectionParameters.overrides.none {
|
||||
it.key.type == TRACK_TYPE_VIDEO
|
||||
}
|
||||
|
||||
val currentIndex = when {
|
||||
isAuto -> {
|
||||
if (player.videoSize.width > 0 && player.videoSize.height > 0) {
|
||||
(0 until group.length).firstOrNull { i ->
|
||||
val format = group.getTrackFormat(i)
|
||||
format.width == player.videoSize.width && format.height == player.videoSize.height
|
||||
}
|
||||
} else null
|
||||
}
|
||||
else -> (0 until group.length).firstOrNull { group.isTrackSelected(it) }
|
||||
} ?: return null
|
||||
|
||||
val format = group.getTrackFormat(currentIndex)
|
||||
return Rendition(
|
||||
id = currentIndex.toString(),
|
||||
width = format.width.toDouble().coerceAtLeast(0.0),
|
||||
height = format.height.toDouble().coerceAtLeast(0.0),
|
||||
bitrate = format.bitrate.toDouble().coerceAtLeast(0.0),
|
||||
selected = true
|
||||
)
|
||||
}
|
||||
|
||||
private fun emitIsAutoQualityChange() {
|
||||
val isAuto = player.trackSelectionParameters.overrides.none {
|
||||
it.key.type == C.TRACK_TYPE_VIDEO
|
||||
}
|
||||
if (isAuto == lastIsAutoQuality) return
|
||||
lastIsAutoQuality = isAuto
|
||||
stateBoolListeners[BoolProperty.ISAUTOQUALITY]?.forEach { it(isAuto) }
|
||||
}
|
||||
|
||||
private fun emitRenditionChange() {
|
||||
val rendition = getCurrentRendition() ?: return
|
||||
if (rendition == lastRendition) return
|
||||
lastRendition = rendition
|
||||
onRenditionChangeListeners.forEach { it(rendition) }
|
||||
}
|
||||
|
||||
override fun onPlaybackStateChanged(playbackState: Int) {
|
||||
val state = when (player.playbackState) {
|
||||
STATE_IDLE -> PlayerStatus.IDLE
|
||||
@@ -108,6 +159,13 @@ class EventMap(private val player: Player) : HybridOmniEventMapSpec(), Player.Li
|
||||
)
|
||||
)
|
||||
}
|
||||
emitIsAutoQualityChange()
|
||||
emitRenditionChange()
|
||||
}
|
||||
|
||||
override fun onVideoSizeChanged(videoSize: VideoSize) {
|
||||
emitIsAutoQualityChange()
|
||||
emitRenditionChange()
|
||||
}
|
||||
|
||||
override fun onPlayerError(error: PlaybackException) {
|
||||
@@ -135,11 +193,9 @@ class EventMap(private val player: Player) : HybridOmniEventMapSpec(), Player.Li
|
||||
newPosition: Player.PositionInfo,
|
||||
reason: Int
|
||||
) {
|
||||
emitCoreState(forceCurrentTime = true)
|
||||
}
|
||||
|
||||
private fun emitCoreState(forceCurrentTime: Boolean) {
|
||||
emitCurrentTime(forceCurrentTime)
|
||||
stateListeners[NumberProperty.CURRENTTIME]?.forEach {
|
||||
it((player.currentPosition.toDouble() / 1000.0).coerceAtLeast(0.0))
|
||||
}
|
||||
stateListeners[NumberProperty.BUFFERED]?.forEach {
|
||||
it((player.totalBufferedDuration.toDouble() / 1000.0).coerceAtLeast(0.0))
|
||||
}
|
||||
@@ -149,15 +205,6 @@ class EventMap(private val player: Player) : HybridOmniEventMapSpec(), Player.Li
|
||||
}
|
||||
}
|
||||
|
||||
private fun emitCurrentTime(force: Boolean) {
|
||||
val now = SystemClock.elapsedRealtime()
|
||||
if (!force && now - lastTimePosDispatchMs < 1000L) return
|
||||
lastTimePosDispatchMs = now
|
||||
stateListeners[NumberProperty.CURRENTTIME]?.forEach {
|
||||
it((player.currentPosition.toDouble() / 1000.0).coerceAtLeast(0.0))
|
||||
}
|
||||
}
|
||||
|
||||
override fun addStateListener(key: NumberProperty, cb: (value: Double) -> Unit) {
|
||||
stateListeners.getOrPut(key) { mutableSetOf() }.add(cb)
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import androidx.media3.common.C.TRACK_TYPE_UNKNOWN
|
||||
import androidx.media3.common.C.TRACK_TYPE_VIDEO
|
||||
import androidx.media3.common.DeviceInfo
|
||||
import androidx.media3.common.Format
|
||||
import androidx.media3.common.Format.NO_VALUE
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.MediaMetadata
|
||||
import androidx.media3.common.PlaybackException
|
||||
@@ -337,12 +338,15 @@ class MpvPlayer(ctx: Context) : BasePlayer(), MPVLib.EventObserver {
|
||||
val label = mpv.getPropertyString("$base/title")
|
||||
val language = mpv.getPropertyString("$base/lang")
|
||||
val codec = mpv.getPropertyString("$base/codec")
|
||||
val bitrate = mpv.getPropertyInt("$base/hls-bitrate")
|
||||
?: mpv.getPropertyInt("$base/demux-bitrate")
|
||||
|
||||
val format = Format.Builder()
|
||||
.setId(id.toString())
|
||||
.setLabel(label)
|
||||
.setLanguage(language)
|
||||
.setCodecs(codec)
|
||||
.setAverageBitrate(bitrate ?: NO_VALUE)
|
||||
.build()
|
||||
|
||||
grouped.getOrPut<Int, MutableList<Entry>>(type) { mutableListOf<Entry>() }
|
||||
@@ -612,13 +616,15 @@ class MpvPlayer(ctx: Context) : BasePlayer(), MPVLib.EventObserver {
|
||||
EVENT_TIMELINE_CHANGED,
|
||||
EVENT_MEDIA_METADATA_CHANGED,
|
||||
EVENT_PLAYBACK_STATE_CHANGED,
|
||||
EVENT_IS_PLAYING_CHANGED
|
||||
EVENT_IS_PLAYING_CHANGED,
|
||||
EVENT_TRACKS_CHANGED
|
||||
)
|
||||
) {
|
||||
it.onTimelineChanged(currentTimeline, TIMELINE_CHANGE_REASON_SOURCE_UPDATE)
|
||||
it.onMediaMetadataChanged(mediaMetadata)
|
||||
it.onPlaybackStateChanged(STATE_READY)
|
||||
it.onIsPlayingChanged(playWhenReady)
|
||||
it.onTracksChanged(getCurrentTracks())
|
||||
}
|
||||
|
||||
MPVLib.MpvEvent.MPV_EVENT_SEEK,
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package dev.zoriya.omni
|
||||
|
||||
import android.R
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.PendingIntent
|
||||
import android.content.Intent
|
||||
import android.media.metrics.TrackChangeEvent.TRACK_TYPE_VIDEO
|
||||
import android.util.Log
|
||||
import android.view.SurfaceHolder
|
||||
import androidx.media3.common.C
|
||||
@@ -33,8 +31,8 @@ import dev.zoriya.omni.utils.ThreadHelper.runOnMainThreadSync
|
||||
class OmniPlayer : HybridOmniPlayerSpec() {
|
||||
private val ctx = NitroModules.applicationContext ?: throw Error("No Context available!")
|
||||
val player: Player = runOnMainThreadSync {
|
||||
// ExoPlayer.Builder(ctx).build()
|
||||
MpvPlayer(ctx)
|
||||
// ExoPlayer.Builder(ctx).build()
|
||||
MpvPlayer(ctx)
|
||||
}
|
||||
override val eventMap = EventMap(player)
|
||||
|
||||
@@ -66,7 +64,7 @@ class OmniPlayer : HybridOmniPlayerSpec() {
|
||||
get() = currentSource
|
||||
?: throw IllegalStateException("source should be initialized before get")
|
||||
set(value) {
|
||||
Log.e("omni", "update source")
|
||||
Log.i("omni", "update source")
|
||||
currentSource = value
|
||||
val src = value.src.firstOrNull()
|
||||
if (src == null) {
|
||||
@@ -204,6 +202,12 @@ class OmniPlayer : HybridOmniPlayerSpec() {
|
||||
override val subtitles by mainThreadProperty { tracksByType(C.TRACK_TYPE_TEXT) }
|
||||
override val rendition by mainThreadProperty { getRenditions() }
|
||||
|
||||
override var isAutoQuality by mainThreadProperty {
|
||||
player.trackSelectionParameters.overrides.none {
|
||||
it.key.type == C.TRACK_TYPE_VIDEO
|
||||
}
|
||||
}
|
||||
|
||||
override fun play() {
|
||||
runOnMainThreadSync { player.play() }
|
||||
}
|
||||
@@ -286,16 +290,28 @@ class OmniPlayer : HybridOmniPlayerSpec() {
|
||||
player.currentTracks.groups.firstOrNull { it.isSelected && it.type == C.TRACK_TYPE_VIDEO }
|
||||
?: return emptyArray()
|
||||
|
||||
val currentIndex = when {
|
||||
isAutoQuality -> {
|
||||
if (player.videoSize.width > 0 && player.videoSize.height > 0) {
|
||||
(0 until group.length).firstOrNull { i ->
|
||||
val format = group.getTrackFormat(i)
|
||||
format.width == player.videoSize.width && format.height == player.videoSize.height
|
||||
}
|
||||
} else null
|
||||
}
|
||||
else -> (0 until group.length).firstOrNull { group.isTrackSelected(it) }
|
||||
}
|
||||
|
||||
val result = ArrayList<Rendition>()
|
||||
for (i in 0 until group.length) {
|
||||
val format = group.getTrackFormat(i)
|
||||
result.add(
|
||||
Rendition(
|
||||
id = format.id ?: group.mediaTrackGroup.id,
|
||||
id = i.toString(),
|
||||
width = format.width.toDouble().coerceAtLeast(0.0),
|
||||
height = format.height.toDouble().coerceAtLeast(0.0),
|
||||
bitrate = format.bitrate.toDouble().coerceAtLeast(0.0),
|
||||
selected = group.isTrackSelected(i)
|
||||
selected = i == currentIndex
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -316,17 +332,10 @@ class OmniPlayer : HybridOmniPlayerSpec() {
|
||||
player.currentTracks.groups.find { it.isSelected && it.type == C.TRACK_TYPE_VIDEO }
|
||||
?: return@runOnMainThreadSync
|
||||
|
||||
for (i in 0 until group.length) {
|
||||
val format = group.getTrackFormat(i)
|
||||
val formatId = format.id ?: group.mediaTrackGroup.id
|
||||
if (formatId == rendition.id) continue
|
||||
|
||||
player.trackSelectionParameters = player.trackSelectionParameters
|
||||
.buildUpon()
|
||||
.setOverrideForType(TrackSelectionOverride(group.mediaTrackGroup, i))
|
||||
.build()
|
||||
return@runOnMainThreadSync
|
||||
}
|
||||
player.trackSelectionParameters = player.trackSelectionParameters
|
||||
.buildUpon()
|
||||
.setOverrideForType(TrackSelectionOverride(group.mediaTrackGroup, rendition.id.toInt()))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,7 +370,7 @@ class OmniPlayerService : MediaSessionService() {
|
||||
.build()
|
||||
|
||||
setMediaNotificationProvider(DefaultMediaNotificationProvider.Builder(this).build().apply {
|
||||
setSmallIcon(applicationInfo.icon.takeIf { it != 0 } ?: R.drawable.ic_media_play)
|
||||
setSmallIcon(applicationInfo.icon.takeIf { it != 0 } ?: android.R.drawable.ic_media_play)
|
||||
})
|
||||
addSession(mediaSession)
|
||||
setShowNotificationForIdlePlayer(SHOW_NOTIFICATION_FOR_IDLE_PLAYER_ALWAYS)
|
||||
|
||||
+12
-12
@@ -1,4 +1,4 @@
|
||||
import { memo, useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import type React from "react";
|
||||
import { Pressable, ScrollView, StyleSheet, Text, View } from "react-native";
|
||||
import {
|
||||
@@ -10,6 +10,12 @@ import {
|
||||
} from "react-native-omni";
|
||||
|
||||
const PLAYLIST = [
|
||||
{
|
||||
title: "elephants dram",
|
||||
artist: "multi audio",
|
||||
album: "Adaptive",
|
||||
uri: "https://playertest.longtailvideo.com/adaptive/elephants_dream_v4/index.m3u8",
|
||||
},
|
||||
{
|
||||
title: "Big Buck Bunny (HLS)",
|
||||
artist: "Blender Foundation",
|
||||
@@ -60,6 +66,7 @@ function PlayerExample({
|
||||
|
||||
const muted = usePlayerState("muted");
|
||||
const volume = usePlayerState("volume");
|
||||
const isAutoQuality = usePlayerState("isAutoQuality");
|
||||
const [logs, setLogs] = useState<string[]>([]);
|
||||
const [tracks, setTracks] = useState(() => ({
|
||||
videos: [...player.videos],
|
||||
@@ -205,11 +212,6 @@ function PlayerExample({
|
||||
refreshTracks();
|
||||
};
|
||||
|
||||
const selectRendition = (rendition?: (typeof tracks.renditions)[number]) => {
|
||||
player.selectRendition(rendition);
|
||||
refreshTracks();
|
||||
};
|
||||
|
||||
return (
|
||||
<ScrollView style={styles.container}>
|
||||
<Text style={styles.heading}>react-native-omni</Text>
|
||||
@@ -369,16 +371,14 @@ function PlayerExample({
|
||||
<Pressable
|
||||
style={[
|
||||
styles.trackButton,
|
||||
!tracks.renditions.some((rendition) => rendition.selected) &&
|
||||
styles.selectedTrackButton,
|
||||
isAutoQuality && styles.selectedTrackButton,
|
||||
]}
|
||||
onPress={() => selectRendition(undefined)}
|
||||
onPress={() => player.selectRendition(undefined)}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
styles.trackButtonText,
|
||||
!tracks.renditions.some((rendition) => rendition.selected) &&
|
||||
styles.selectedTrackButtonText,
|
||||
isAutoQuality && styles.selectedTrackButtonText,
|
||||
]}
|
||||
>
|
||||
Auto
|
||||
@@ -394,7 +394,7 @@ function PlayerExample({
|
||||
styles.trackButton,
|
||||
rendition.selected && styles.selectedTrackButton,
|
||||
]}
|
||||
onPress={() => selectRendition(rendition)}
|
||||
onPress={() => player.selectRendition(rendition)}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
|
||||
@@ -48,6 +48,9 @@ namespace margelo::nitro::omni {
|
||||
case BoolProperty::MUTED:
|
||||
static const auto fieldMUTED = clazz->getStaticField<JBoolProperty>("MUTED");
|
||||
return clazz->getStaticFieldValue(fieldMUTED);
|
||||
case BoolProperty::ISAUTOQUALITY:
|
||||
static const auto fieldISAUTOQUALITY = clazz->getStaticField<JBoolProperty>("ISAUTOQUALITY");
|
||||
return clazz->getStaticFieldValue(fieldISAUTOQUALITY);
|
||||
default:
|
||||
std::string stringValue = std::to_string(static_cast<int>(value));
|
||||
throw std::invalid_argument("Invalid enum value (" + stringValue + "!");
|
||||
|
||||
@@ -225,6 +225,11 @@ namespace margelo::nitro::omni {
|
||||
static const auto method = _javaPart->javaClassStatic()->getMethod<void(jboolean /* muted */)>("setMuted");
|
||||
method(_javaPart, muted);
|
||||
}
|
||||
bool JHybridOmniPlayerSpec::getIsAutoQuality() {
|
||||
static const auto method = _javaPart->javaClassStatic()->getMethod<jboolean()>("isAutoQuality");
|
||||
auto __result = method(_javaPart);
|
||||
return static_cast<bool>(__result);
|
||||
}
|
||||
|
||||
// Methods
|
||||
void JHybridOmniPlayerSpec::play() {
|
||||
|
||||
@@ -73,6 +73,7 @@ namespace margelo::nitro::omni {
|
||||
void setVolume(double volume) override;
|
||||
bool getMuted() override;
|
||||
void setMuted(bool muted) override;
|
||||
bool getIsAutoQuality() override;
|
||||
|
||||
public:
|
||||
// Methods
|
||||
|
||||
@@ -57,6 +57,9 @@ namespace margelo::nitro::omni {
|
||||
case NumberProperty::VOLUME:
|
||||
static const auto fieldVOLUME = clazz->getStaticField<JNumberProperty>("VOLUME");
|
||||
return clazz->getStaticFieldValue(fieldVOLUME);
|
||||
case NumberProperty::ISAUTOQUALITY:
|
||||
static const auto fieldISAUTOQUALITY = clazz->getStaticField<JNumberProperty>("ISAUTOQUALITY");
|
||||
return clazz->getStaticFieldValue(fieldISAUTOQUALITY);
|
||||
default:
|
||||
std::string stringValue = std::to_string(static_cast<int>(value));
|
||||
throw std::invalid_argument("Invalid enum value (" + stringValue + "!");
|
||||
|
||||
@@ -17,7 +17,8 @@ import com.facebook.proguard.annotations.DoNotStrip
|
||||
@Keep
|
||||
enum class BoolProperty(@DoNotStrip @Keep val value: Int) {
|
||||
ISPLAYING(0),
|
||||
MUTED(1);
|
||||
MUTED(1),
|
||||
ISAUTOQUALITY(2);
|
||||
|
||||
companion object
|
||||
}
|
||||
|
||||
+4
@@ -104,6 +104,10 @@ abstract class HybridOmniPlayerSpec: HybridObject() {
|
||||
@set:DoNotStrip
|
||||
@set:Keep
|
||||
abstract var muted: Boolean
|
||||
|
||||
@get:DoNotStrip
|
||||
@get:Keep
|
||||
abstract val isAutoQuality: Boolean
|
||||
|
||||
// Methods
|
||||
@DoNotStrip
|
||||
|
||||
+2
-1
@@ -20,7 +20,8 @@ enum class NumberProperty(@DoNotStrip @Keep val value: Int) {
|
||||
BUFFERED(1),
|
||||
DURATION(2),
|
||||
PLAYBACKRATE(3),
|
||||
VOLUME(4);
|
||||
VOLUME(4),
|
||||
ISAUTOQUALITY(5);
|
||||
|
||||
companion object
|
||||
}
|
||||
|
||||
+4
@@ -31,6 +31,7 @@ namespace margelo::nitro::omni {
|
||||
enum class BoolProperty {
|
||||
ISPLAYING SWIFT_NAME(isplaying) = 0,
|
||||
MUTED SWIFT_NAME(muted) = 1,
|
||||
ISAUTOQUALITY SWIFT_NAME(isautoquality) = 2,
|
||||
} CLOSED_ENUM;
|
||||
|
||||
} // namespace margelo::nitro::omni
|
||||
@@ -45,6 +46,7 @@ namespace margelo::nitro {
|
||||
switch (hashString(unionValue.c_str(), unionValue.size())) {
|
||||
case hashString("isPlaying"): return margelo::nitro::omni::BoolProperty::ISPLAYING;
|
||||
case hashString("muted"): return margelo::nitro::omni::BoolProperty::MUTED;
|
||||
case hashString("isAutoQuality"): return margelo::nitro::omni::BoolProperty::ISAUTOQUALITY;
|
||||
default: [[unlikely]]
|
||||
throw std::invalid_argument("Cannot convert \"" + unionValue + "\" to enum BoolProperty - invalid value!");
|
||||
}
|
||||
@@ -53,6 +55,7 @@ namespace margelo::nitro {
|
||||
switch (arg) {
|
||||
case margelo::nitro::omni::BoolProperty::ISPLAYING: return JSIConverter<std::string>::toJSI(runtime, "isPlaying");
|
||||
case margelo::nitro::omni::BoolProperty::MUTED: return JSIConverter<std::string>::toJSI(runtime, "muted");
|
||||
case margelo::nitro::omni::BoolProperty::ISAUTOQUALITY: return JSIConverter<std::string>::toJSI(runtime, "isAutoQuality");
|
||||
default: [[unlikely]]
|
||||
throw std::invalid_argument("Cannot convert BoolProperty to JS - invalid value: "
|
||||
+ std::to_string(static_cast<int>(arg)) + "!");
|
||||
@@ -66,6 +69,7 @@ namespace margelo::nitro {
|
||||
switch (hashString(unionValue.c_str(), unionValue.size())) {
|
||||
case hashString("isPlaying"):
|
||||
case hashString("muted"):
|
||||
case hashString("isAutoQuality"):
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace margelo::nitro::omni {
|
||||
prototype.registerHybridSetter("volume", &HybridOmniPlayerSpec::setVolume);
|
||||
prototype.registerHybridGetter("muted", &HybridOmniPlayerSpec::getMuted);
|
||||
prototype.registerHybridSetter("muted", &HybridOmniPlayerSpec::setMuted);
|
||||
prototype.registerHybridGetter("isAutoQuality", &HybridOmniPlayerSpec::getIsAutoQuality);
|
||||
prototype.registerHybridMethod("play", &HybridOmniPlayerSpec::play);
|
||||
prototype.registerHybridMethod("pause", &HybridOmniPlayerSpec::pause);
|
||||
prototype.registerHybridMethod("seekBy", &HybridOmniPlayerSpec::seekBy);
|
||||
|
||||
@@ -83,6 +83,7 @@ namespace margelo::nitro::omni {
|
||||
virtual void setVolume(double volume) = 0;
|
||||
virtual bool getMuted() = 0;
|
||||
virtual void setMuted(bool muted) = 0;
|
||||
virtual bool getIsAutoQuality() = 0;
|
||||
|
||||
public:
|
||||
// Methods
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace margelo::nitro::omni {
|
||||
DURATION SWIFT_NAME(duration) = 2,
|
||||
PLAYBACKRATE SWIFT_NAME(playbackrate) = 3,
|
||||
VOLUME SWIFT_NAME(volume) = 4,
|
||||
ISAUTOQUALITY SWIFT_NAME(isautoquality) = 5,
|
||||
} CLOSED_ENUM;
|
||||
|
||||
} // namespace margelo::nitro::omni
|
||||
@@ -51,6 +52,7 @@ namespace margelo::nitro {
|
||||
case hashString("duration"): return margelo::nitro::omni::NumberProperty::DURATION;
|
||||
case hashString("playbackRate"): return margelo::nitro::omni::NumberProperty::PLAYBACKRATE;
|
||||
case hashString("volume"): return margelo::nitro::omni::NumberProperty::VOLUME;
|
||||
case hashString("isAutoQuality"): return margelo::nitro::omni::NumberProperty::ISAUTOQUALITY;
|
||||
default: [[unlikely]]
|
||||
throw std::invalid_argument("Cannot convert \"" + unionValue + "\" to enum NumberProperty - invalid value!");
|
||||
}
|
||||
@@ -62,6 +64,7 @@ namespace margelo::nitro {
|
||||
case margelo::nitro::omni::NumberProperty::DURATION: return JSIConverter<std::string>::toJSI(runtime, "duration");
|
||||
case margelo::nitro::omni::NumberProperty::PLAYBACKRATE: return JSIConverter<std::string>::toJSI(runtime, "playbackRate");
|
||||
case margelo::nitro::omni::NumberProperty::VOLUME: return JSIConverter<std::string>::toJSI(runtime, "volume");
|
||||
case margelo::nitro::omni::NumberProperty::ISAUTOQUALITY: return JSIConverter<std::string>::toJSI(runtime, "isAutoQuality");
|
||||
default: [[unlikely]]
|
||||
throw std::invalid_argument("Cannot convert NumberProperty to JS - invalid value: "
|
||||
+ std::to_string(static_cast<int>(arg)) + "!");
|
||||
@@ -78,6 +81,7 @@ namespace margelo::nitro {
|
||||
case hashString("duration"):
|
||||
case hashString("playbackRate"):
|
||||
case hashString("volume"):
|
||||
case hashString("isAutoQuality"):
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
||||
@@ -46,6 +46,7 @@ export function usePlayerState<Key extends keyof OmniPlayerState>(
|
||||
return () => em.removeStateListener(key, setState);
|
||||
case "isPlaying":
|
||||
case "muted":
|
||||
case "isAutoQuality":
|
||||
em.addStateBoolListener(key, setState);
|
||||
return () => em.removeStateBoolListener(key, setState);
|
||||
case "status":
|
||||
|
||||
@@ -11,7 +11,7 @@ export type NumberProperty = Exclude<
|
||||
keyof OmniPlayerState,
|
||||
"status" | "isPlaying" | "muted"
|
||||
>;
|
||||
export type BoolProperty = "isPlaying" | "muted";
|
||||
export type BoolProperty = "isPlaying" | "muted" | "isAutoQuality";
|
||||
|
||||
export interface OmniEventMap extends HybridObject<{ android: "kotlin" }> {
|
||||
addStateListener(key: NumberProperty, cb: (value: number) => void): void;
|
||||
|
||||
+10
-9
@@ -34,21 +34,22 @@ export interface OmniPlayerState {
|
||||
// between 0 and 1
|
||||
volume: number;
|
||||
muted: boolean;
|
||||
readonly isAutoQuality: boolean
|
||||
}
|
||||
|
||||
export type PlayerStatus = "idle" | "loading" | "readyToPlay" | "error";
|
||||
|
||||
export interface Track {
|
||||
id: string;
|
||||
label?: string;
|
||||
language?: string;
|
||||
selected: boolean;
|
||||
readonly id: string;
|
||||
readonly label?: string;
|
||||
readonly language?: string;
|
||||
readonly selected: boolean;
|
||||
}
|
||||
|
||||
export interface Rendition {
|
||||
id: string;
|
||||
width: number;
|
||||
height: number;
|
||||
bitrate: number;
|
||||
selected: boolean;
|
||||
readonly id: string;
|
||||
readonly width: number;
|
||||
readonly height: number;
|
||||
readonly bitrate: number;
|
||||
readonly selected: boolean;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user