diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
index 7db277c..de57c05 100644
--- a/android/src/main/AndroidManifest.xml
+++ b/android/src/main/AndroidManifest.xml
@@ -16,12 +16,5 @@
-
diff --git a/android/src/main/java/dev/zoriya/omni/OmniCastOptionsProvider.kt b/android/src/main/java/dev/zoriya/omni/OmniCastOptionsProvider.kt
index 2e5a2b9..a29d095 100644
--- a/android/src/main/java/dev/zoriya/omni/OmniCastOptionsProvider.kt
+++ b/android/src/main/java/dev/zoriya/omni/OmniCastOptionsProvider.kt
@@ -4,8 +4,6 @@ import android.content.Context
import com.google.android.gms.cast.CastMediaControlIntent
import com.google.android.gms.cast.framework.CastOptions
import com.google.android.gms.cast.framework.media.CastMediaOptions
-import com.google.android.gms.cast.framework.media.MediaIntentReceiver
-import com.google.android.gms.cast.framework.media.NotificationOptions
import com.google.android.gms.cast.framework.OptionsProvider
import com.google.android.gms.cast.framework.SessionProvider
@@ -14,23 +12,9 @@ class OmniCastOptionsProvider : OptionsProvider {
val appId = OmniPlayer.receiverApplicationId
?: CastMediaControlIntent.DEFAULT_MEDIA_RECEIVER_APPLICATION_ID
- val notificationOptions = NotificationOptions.Builder()
- .setActions(
- listOf(
- MediaIntentReceiver.ACTION_SKIP_PREV,
- MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK,
- MediaIntentReceiver.ACTION_SKIP_NEXT,
- ),
- intArrayOf(0, 1, 2),
- )
- .setSmallIconDrawableResId(
- androidx.media3.session.R.drawable.media3_notification_small_icon
- )
- .setTargetActivityClassName(OmniCastTapActivity::class.java.name)
- .build()
-
val mediaOptions = CastMediaOptions.Builder()
- .setNotificationOptions(notificationOptions)
+ .setMediaSessionEnabled(false)
+ .setNotificationOptions(null)
.build()
return CastOptions.Builder()
diff --git a/android/src/main/java/dev/zoriya/omni/OmniCastTapActivity.kt b/android/src/main/java/dev/zoriya/omni/OmniCastTapActivity.kt
deleted file mode 100644
index 2fc3719..0000000
--- a/android/src/main/java/dev/zoriya/omni/OmniCastTapActivity.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-package dev.zoriya.omni
-
-import android.app.Activity
-import android.content.Context
-import android.content.Intent
-import android.os.Bundle
-import androidx.core.net.toUri
-
-class OmniCastTapActivity : Activity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- val url = getSharedPreferences(OmniPlayer.OMNI_PREFS, Context.MODE_PRIVATE)
- .getString(OmniPlayer.NOTIFICATION_URL_PREF, null)
- val intent = url
- ?.let { Intent(Intent.ACTION_VIEW, it.toUri()).setPackage(packageName) }
- ?: packageManager.getLaunchIntentForPackage(packageName)
-
- try {
- startActivity(
- intent?.apply {
- addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP)
- }
- )
- } catch (e: Throwable) {
- android.util.Log.w("OmniPlayer", "could not open $url", e)
- }
- finish()
- }
-}
diff --git a/android/src/main/java/dev/zoriya/omni/OmniPlayer.kt b/android/src/main/java/dev/zoriya/omni/OmniPlayer.kt
index b9eea17..c4b6f14 100644
--- a/android/src/main/java/dev/zoriya/omni/OmniPlayer.kt
+++ b/android/src/main/java/dev/zoriya/omni/OmniPlayer.kt
@@ -104,7 +104,8 @@ class OmniPlayer(
private val castStateListener = CastStateListener {
eventMap.emitCastStatus(computeCastStatus())
listenToReceiver()
- syncNotificationService()
+ // we were only kept alive to hold this cast, it is over now
+ if (abandoned && !isCasting) release()
}
// receivers have no queue to skip in (a queue would make them play things on
@@ -128,12 +129,7 @@ class OmniPlayer(
val player: Player = runOnMainThreadSync {
castOptions?.receiverApplicationId?.let { receiverApplicationId = it }
- // the cast notification outlives the app, so OmniCastTapActivity has to find the
- // url back even when nothing of ours ran in that process yet.
- ctx.getSharedPreferences(OMNI_PREFS, Context.MODE_PRIVATE)
- .edit()
- .putString(NOTIFICATION_URL_PREF, castOptions?.notificationUrl)
- .apply()
+ notificationUrl = castOptions?.notificationUrl
val cc = try {
CastContext.getSharedInstance(ctx)
} catch (_: Throwable) {
@@ -172,24 +168,26 @@ class OmniPlayer(
private var serviceRunning = false
private fun syncNotificationService() {
- val shouldShow = showNotification == true && source != null &&
- !runOnMainThreadSync { isCasting }
+ if (abandoned) return
+ val shouldShow = showNotification == true && source != null
when {
shouldShow && !serviceRunning -> {
val otherIsPlaying = notificationPlayer?.let { other ->
- other !== player && runOnMainThreadSync { other.isPlaying }
+ // an abandoned one only holds it until the cast it kept alive ends
+ other !== this && !other.abandoned &&
+ runOnMainThreadSync { other.player.isPlaying }
} == true
if (otherIsPlaying) {
throw Error("Two players can't display notifications at the same time.")
}
- notificationPlayer = player
+ notificationPlayer = this
ctx.startForegroundService(Intent(ctx, OmniPlayerService::class.java))
serviceRunning = true
}
!shouldShow && serviceRunning -> {
ctx.stopService(Intent(ctx, OmniPlayerService::class.java))
- if (notificationPlayer == player) notificationPlayer = null
+ if (notificationPlayer === this) notificationPlayer = null
serviceRunning = false
}
}
@@ -229,22 +227,36 @@ class OmniPlayer(
}
}
+ // the app let go of us. while casting we stay alive anyway: OmniPlayerService holds the
+ // process (and thus the session) up, and its notification is the only remote left - we
+ // keep owning both until castStateListener sees the cast end.
@Volatile
- private var released = false
+ private var abandoned = false
- override fun release() {
- if (released) return
- released = true
- showNotification = false
+ override fun abandon() {
+ if (abandoned) return
+ abandoned = true
+ if (!runOnMainThreadSync { isCasting }) release()
+ }
+
+ // drop everything. this ends the cast session, so it only runs once there is no cast
+ // left to hold (either there was none, or it just ended).
+ private fun release() {
runOnMainThread {
- eventMap.dispose()
castContext?.removeCastStateListener(castStateListener)
- if (!isCasting) player.release()
+ if (notificationPlayer === this) {
+ // syncNotificationService ignores us now, hand the service back ourselves
+ ctx.stopService(Intent(ctx, OmniPlayerService::class.java))
+ notificationPlayer = null
+ serviceRunning = false
+ }
+ eventMap.dispose()
+ player.release()
}
}
override fun dispose() {
- release()
+ abandon()
super.dispose()
}
@@ -641,7 +653,7 @@ class OmniPlayer(
}
companion object {
- var notificationPlayer: Player? = null
+ var notificationPlayer: OmniPlayer? = null
// MediaItem RequestMetadata extras keys carrying cast-only data.
const val CAST_ID_EXTRA = "dev.zoriya.omni.castId"
@@ -655,9 +667,8 @@ class OmniPlayer(
// prop; read by OmniCastOptionsProvider when the Cast SDK initializes.
var receiverApplicationId: String? = null
- // `cast.notificationUrl`, read back by OmniCastTapActivity.
- const val OMNI_PREFS = "dev.zoriya.omni"
- const val NOTIFICATION_URL_PREF = "notificationUrl"
+ // `cast.notificationUrl`, opened when our notification is tapped.
+ var notificationUrl: String? = null
}
}
@@ -668,24 +679,14 @@ class OmniPlayerService : MediaSessionService() {
override fun onCreate() {
super.onCreate()
- val available = OmniPlayer.notificationPlayer
+ val available = OmniPlayer.notificationPlayer?.player
if (available == null) {
startForeground(1, createImmediateNotification())
stopSelf()
return
}
player = available
- val launchIntent = packageManager.getLaunchIntentForPackage(packageName)?.apply {
- addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
- }
- val sessionActivity = launchIntent?.let {
- PendingIntent.getActivity(
- this,
- 0,
- it,
- PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
- )
- }
+ val sessionActivity = openIntent()
mediaSession = MediaSession.Builder(this, player)
.apply {
sessionActivity?.let { setSessionActivity(it) }
@@ -701,7 +702,7 @@ class OmniPlayerService : MediaSessionService() {
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
- val current = OmniPlayer.notificationPlayer
+ val current = OmniPlayer.notificationPlayer?.player
if (current != null && ::mediaSession.isInitialized && mediaSession.player !== current) {
player = current
mediaSession.player = current
@@ -721,25 +722,29 @@ class OmniPlayerService : MediaSessionService() {
manager.createNotificationChannel(channel)
}
- val launchIntent = packageManager.getLaunchIntentForPackage(packageName)?.apply {
- addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
- }
- val pendingIntent = PendingIntent.getActivity(
- this,
- 0,
- launchIntent,
- PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
- )
-
return NotificationCompat.Builder(this, "omni_playback")
.setSmallIcon(androidx.media3.session.R.drawable.media3_notification_small_icon)
.setContentTitle("Omni Player")
.setContentText("Preparing playback...")
- .setContentIntent(pendingIntent)
+ .setContentIntent(openIntent())
.setOngoing(true)
.build()
}
+ private fun openIntent(): PendingIntent? {
+ val intent = OmniPlayer.notificationUrl
+ ?.let { Intent(Intent.ACTION_VIEW, it.toUri()).setPackage(packageName) }
+ ?: packageManager.getLaunchIntentForPackage(packageName)
+ ?: return null
+ intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
+ return PendingIntent.getActivity(
+ this,
+ 0,
+ intent,
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
+ )
+ }
+
override fun onGetSession(controllerInfo: MediaSession.ControllerInfo) = mediaSession
override fun onTaskRemoved(rootIntent: Intent?) {
diff --git a/android/src/main/java/dev/zoriya/omni/OmniPlayerFactory.kt b/android/src/main/java/dev/zoriya/omni/OmniPlayerFactory.kt
index b5f9d62..22e58dc 100755
--- a/android/src/main/java/dev/zoriya/omni/OmniPlayerFactory.kt
+++ b/android/src/main/java/dev/zoriya/omni/OmniPlayerFactory.kt
@@ -6,16 +6,12 @@ import com.margelo.nitro.omni.CastOptions
import com.margelo.nitro.omni.HybridOmniPlayerFactorySpec
import com.margelo.nitro.omni.HybridOmniPlayerSpec
import com.margelo.nitro.omni.PlayerBackend
-import com.margelo.nitro.omni.Source
class OmniPlayerFactory(val context: ThemedReactContext) : HybridOmniPlayerFactorySpec() {
override fun createPlayer(
- props: Source?,
backend: PlayerBackend?,
cast: CastOptions?,
): HybridOmniPlayerSpec {
- return OmniPlayer(backend?.android ?: AndroidBackend.VLC, cast).apply {
- source = props
- }
+ return OmniPlayer(backend?.android ?: AndroidBackend.VLC, cast)
}
}
diff --git a/nitrogen/generated/android/c++/JHybridOmniPlayerFactorySpec.cpp b/nitrogen/generated/android/c++/JHybridOmniPlayerFactorySpec.cpp
index 914bcdf..709ec72 100644
--- a/nitrogen/generated/android/c++/JHybridOmniPlayerFactorySpec.cpp
+++ b/nitrogen/generated/android/c++/JHybridOmniPlayerFactorySpec.cpp
@@ -9,16 +9,6 @@
// Forward declaration of `HybridOmniPlayerSpec` to properly resolve imports.
namespace margelo::nitro::omni { class HybridOmniPlayerSpec; }
-// Forward declaration of `Source` to properly resolve imports.
-namespace margelo::nitro::omni { struct Source; }
-// Forward declaration of `VideoSrc` to properly resolve imports.
-namespace margelo::nitro::omni { struct VideoSrc; }
-// Forward declaration of `Subtitle` to properly resolve imports.
-namespace margelo::nitro::omni { struct Subtitle; }
-// Forward declaration of `Metadata` to properly resolve imports.
-namespace margelo::nitro::omni { struct Metadata; }
-// Forward declaration of `MixAudioMode` to properly resolve imports.
-namespace margelo::nitro::omni { enum class MixAudioMode; }
// Forward declaration of `PlayerBackend` to properly resolve imports.
namespace margelo::nitro::omni { struct PlayerBackend; }
// Forward declaration of `AndroidBackend` to properly resolve imports.
@@ -29,26 +19,14 @@ namespace margelo::nitro::omni { struct CastOptions; }
#include
#include "HybridOmniPlayerSpec.hpp"
#include "JHybridOmniPlayerSpec.hpp"
-#include "Source.hpp"
-#include
-#include "JSource.hpp"
-#include "VideoSrc.hpp"
-#include "JVideoSrc.hpp"
-#include
-#include
-#include "Subtitle.hpp"
-#include
-#include "JSubtitle.hpp"
-#include "Metadata.hpp"
-#include "JMetadata.hpp"
-#include "MixAudioMode.hpp"
-#include "JMixAudioMode.hpp"
#include "PlayerBackend.hpp"
+#include
#include "JPlayerBackend.hpp"
#include "AndroidBackend.hpp"
#include "JAndroidBackend.hpp"
#include "CastOptions.hpp"
#include "JCastOptions.hpp"
+#include
namespace margelo::nitro::omni {
@@ -83,9 +61,9 @@ namespace margelo::nitro::omni {
// Methods
- std::shared_ptr JHybridOmniPlayerFactorySpec::createPlayer(const std::optional& props, const std::optional& backend, const std::optional& cast) {
- static const auto method = _javaPart->javaClassStatic()->getMethod(jni::alias_ref /* props */, jni::alias_ref /* backend */, jni::alias_ref /* cast */)>("createPlayer");
- auto __result = method(_javaPart, props.has_value() ? JSource::fromCpp(props.value()) : nullptr, backend.has_value() ? JPlayerBackend::fromCpp(backend.value()) : nullptr, cast.has_value() ? JCastOptions::fromCpp(cast.value()) : nullptr);
+ std::shared_ptr JHybridOmniPlayerFactorySpec::createPlayer(const std::optional& backend, const std::optional& cast) {
+ static const auto method = _javaPart->javaClassStatic()->getMethod(jni::alias_ref /* backend */, jni::alias_ref /* cast */)>("createPlayer");
+ auto __result = method(_javaPart, backend.has_value() ? JPlayerBackend::fromCpp(backend.value()) : nullptr, cast.has_value() ? JCastOptions::fromCpp(cast.value()) : nullptr);
return __result->getJHybridOmniPlayerSpec();
}
diff --git a/nitrogen/generated/android/c++/JHybridOmniPlayerFactorySpec.hpp b/nitrogen/generated/android/c++/JHybridOmniPlayerFactorySpec.hpp
index 151ef7a..ec6d2f4 100644
--- a/nitrogen/generated/android/c++/JHybridOmniPlayerFactorySpec.hpp
+++ b/nitrogen/generated/android/c++/JHybridOmniPlayerFactorySpec.hpp
@@ -54,7 +54,7 @@ namespace margelo::nitro::omni {
public:
// Methods
- std::shared_ptr createPlayer(const std::optional& props, const std::optional& backend, const std::optional& cast) override;
+ std::shared_ptr createPlayer(const std::optional& backend, const std::optional& cast) override;
private:
jni::global_ref _javaPart;
diff --git a/nitrogen/generated/android/c++/JHybridOmniPlayerSpec.cpp b/nitrogen/generated/android/c++/JHybridOmniPlayerSpec.cpp
index c25b88f..94371f8 100644
--- a/nitrogen/generated/android/c++/JHybridOmniPlayerSpec.cpp
+++ b/nitrogen/generated/android/c++/JHybridOmniPlayerSpec.cpp
@@ -241,8 +241,8 @@ namespace margelo::nitro::omni {
}
// Methods
- void JHybridOmniPlayerSpec::release() {
- static const auto method = _javaPart->javaClassStatic()->getMethod("release");
+ void JHybridOmniPlayerSpec::abandon() {
+ static const auto method = _javaPart->javaClassStatic()->getMethod("abandon");
method(_javaPart);
}
void JHybridOmniPlayerSpec::play() {
diff --git a/nitrogen/generated/android/c++/JHybridOmniPlayerSpec.hpp b/nitrogen/generated/android/c++/JHybridOmniPlayerSpec.hpp
index 1198e01..6e4d09e 100644
--- a/nitrogen/generated/android/c++/JHybridOmniPlayerSpec.hpp
+++ b/nitrogen/generated/android/c++/JHybridOmniPlayerSpec.hpp
@@ -78,7 +78,7 @@ namespace margelo::nitro::omni {
public:
// Methods
- void release() override;
+ void abandon() override;
void play() override;
void pause() override;
void seekBy(double offset) override;
diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniPlayerFactorySpec.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniPlayerFactorySpec.kt
index 34c5206..4d80005 100644
--- a/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniPlayerFactorySpec.kt
+++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniPlayerFactorySpec.kt
@@ -30,7 +30,7 @@ abstract class HybridOmniPlayerFactorySpec: HybridObject() {
// Methods
@DoNotStrip
@Keep
- abstract fun createPlayer(props: Source?, backend: PlayerBackend?, cast: CastOptions?): HybridOmniPlayerSpec
+ abstract fun createPlayer(backend: PlayerBackend?, cast: CastOptions?): HybridOmniPlayerSpec
// Default implementation of `HybridObject.toString()`
override fun toString(): String {
diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniPlayerSpec.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniPlayerSpec.kt
index 2896a89..d3289bd 100644
--- a/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniPlayerSpec.kt
+++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniPlayerSpec.kt
@@ -116,7 +116,7 @@ abstract class HybridOmniPlayerSpec: HybridObject() {
// Methods
@DoNotStrip
@Keep
- abstract fun release(): Unit
+ abstract fun abandon(): Unit
@DoNotStrip
@Keep
diff --git a/nitrogen/generated/shared/c++/HybridOmniPlayerFactorySpec.hpp b/nitrogen/generated/shared/c++/HybridOmniPlayerFactorySpec.hpp
index d192a0b..b787ac5 100644
--- a/nitrogen/generated/shared/c++/HybridOmniPlayerFactorySpec.hpp
+++ b/nitrogen/generated/shared/c++/HybridOmniPlayerFactorySpec.hpp
@@ -15,8 +15,6 @@
// Forward declaration of `HybridOmniPlayerSpec` to properly resolve imports.
namespace margelo::nitro::omni { class HybridOmniPlayerSpec; }
-// Forward declaration of `Source` to properly resolve imports.
-namespace margelo::nitro::omni { struct Source; }
// Forward declaration of `PlayerBackend` to properly resolve imports.
namespace margelo::nitro::omni { struct PlayerBackend; }
// Forward declaration of `CastOptions` to properly resolve imports.
@@ -24,9 +22,8 @@ namespace margelo::nitro::omni { struct CastOptions; }
#include
#include "HybridOmniPlayerSpec.hpp"
-#include "Source.hpp"
-#include
#include "PlayerBackend.hpp"
+#include
#include "CastOptions.hpp"
namespace margelo::nitro::omni {
@@ -60,7 +57,7 @@ namespace margelo::nitro::omni {
public:
// Methods
- virtual std::shared_ptr createPlayer(const std::optional& props, const std::optional& backend, const std::optional& cast) = 0;
+ virtual std::shared_ptr createPlayer(const std::optional& backend, const std::optional& cast) = 0;
protected:
// Hybrid Setup
diff --git a/nitrogen/generated/shared/c++/HybridOmniPlayerSpec.cpp b/nitrogen/generated/shared/c++/HybridOmniPlayerSpec.cpp
index 40ff406..e2d4746 100644
--- a/nitrogen/generated/shared/c++/HybridOmniPlayerSpec.cpp
+++ b/nitrogen/generated/shared/c++/HybridOmniPlayerSpec.cpp
@@ -39,7 +39,7 @@ namespace margelo::nitro::omni {
prototype.registerHybridGetter("audios", &HybridOmniPlayerSpec::getAudios);
prototype.registerHybridGetter("subtitles", &HybridOmniPlayerSpec::getSubtitles);
prototype.registerHybridGetter("renditions", &HybridOmniPlayerSpec::getRenditions);
- prototype.registerHybridMethod("release", &HybridOmniPlayerSpec::release);
+ prototype.registerHybridMethod("abandon", &HybridOmniPlayerSpec::abandon);
prototype.registerHybridMethod("play", &HybridOmniPlayerSpec::play);
prototype.registerHybridMethod("pause", &HybridOmniPlayerSpec::pause);
prototype.registerHybridMethod("seekBy", &HybridOmniPlayerSpec::seekBy);
diff --git a/nitrogen/generated/shared/c++/HybridOmniPlayerSpec.hpp b/nitrogen/generated/shared/c++/HybridOmniPlayerSpec.hpp
index 9b727e0..bfab3ec 100644
--- a/nitrogen/generated/shared/c++/HybridOmniPlayerSpec.hpp
+++ b/nitrogen/generated/shared/c++/HybridOmniPlayerSpec.hpp
@@ -91,7 +91,7 @@ namespace margelo::nitro::omni {
public:
// Methods
- virtual void release() = 0;
+ virtual void abandon() = 0;
virtual void play() = 0;
virtual void pause() = 0;
virtual void seekBy(double offset) = 0;
diff --git a/src/provider.tsx b/src/provider.tsx
index d47bf74..80c16ab 100755
--- a/src/provider.tsx
+++ b/src/provider.tsx
@@ -35,7 +35,7 @@ export const OmniProvider = ({
const [player, setPlayer] = useState(null);
const createPlayer = useEffectEvent((aBackend: AndroidBackend) =>
- ProviderFactory.createPlayer(source, { android: aBackend }, cast),
+ ProviderFactory.createPlayer({ android: aBackend }, cast),
);
useEffect(() => {
@@ -44,11 +44,14 @@ export const OmniProvider = ({
useEffect(() => {
if (!player) return;
- return () => player.release();
+ return () => player.abandon();
}, [player]);
useEffect(() => {
- if (player) player.source = source;
+ if (!player) return;
+ // early return on init to keep running cast sessions active
+ if (source == null && player.source == null) return;
+ player.source = source;
}, [player, source]);
useEffect(() => {
diff --git a/src/specs/omni-player.nitro.ts b/src/specs/omni-player.nitro.ts
index 693ec9e..0ea4a60 100644
--- a/src/specs/omni-player.nitro.ts
+++ b/src/specs/omni-player.nitro.ts
@@ -81,13 +81,10 @@ export interface OmniPlayer
OmniPlayerT {
readonly eventMap: OmniEventMap;
- release(): void;
+ // let go of the player. it stays alive as long as it holds a cast session (android).
+ abandon(): void;
}
export interface OmniPlayerFactory extends HybridObject<{ android: "kotlin" }> {
- createPlayer(
- props?: Source,
- backend?: PlayerBackend,
- cast?: CastOptions,
- ): OmniPlayer;
+ createPlayer(backend?: PlayerBackend, cast?: CastOptions): OmniPlayer;
}