mirror of
https://github.com/zoriya/react-native-omni.git
synced 2026-08-16 02:44:51 +00:00
Handle track selection
This commit is contained in:
@@ -4,6 +4,7 @@ import android.R
|
|||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.media.metrics.TrackChangeEvent.TRACK_TYPE_VIDEO
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.SurfaceHolder
|
import android.view.SurfaceHolder
|
||||||
import androidx.media3.common.C
|
import androidx.media3.common.C
|
||||||
@@ -20,14 +21,13 @@ import androidx.core.net.toUri
|
|||||||
import androidx.media3.common.MediaItem.RequestMetadata
|
import androidx.media3.common.MediaItem.RequestMetadata
|
||||||
import androidx.media3.common.MediaItem.SubtitleConfiguration
|
import androidx.media3.common.MediaItem.SubtitleConfiguration
|
||||||
import androidx.media3.common.TrackSelectionOverride
|
import androidx.media3.common.TrackSelectionOverride
|
||||||
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
import androidx.media3.session.DefaultMediaNotificationProvider
|
import androidx.media3.session.DefaultMediaNotificationProvider
|
||||||
import androidx.media3.session.MediaSession
|
import androidx.media3.session.MediaSession
|
||||||
import androidx.media3.session.MediaSessionService
|
import androidx.media3.session.MediaSessionService
|
||||||
import dev.zoriya.omni.utils.ThreadHelper.mainThreadProperty
|
import dev.zoriya.omni.utils.ThreadHelper.mainThreadProperty
|
||||||
import dev.zoriya.omni.utils.ThreadHelper.runOnMainThread
|
import dev.zoriya.omni.utils.ThreadHelper.runOnMainThread
|
||||||
import dev.zoriya.omni.utils.ThreadHelper.runOnMainThreadSync
|
import dev.zoriya.omni.utils.ThreadHelper.runOnMainThreadSync
|
||||||
import kotlinx.coroutines.InternalCoroutinesApi
|
|
||||||
import kotlinx.coroutines.internal.synchronized
|
|
||||||
|
|
||||||
@SuppressLint("UnsafeOptInUsageError")
|
@SuppressLint("UnsafeOptInUsageError")
|
||||||
class OmniPlayer : HybridOmniPlayerSpec() {
|
class OmniPlayer : HybridOmniPlayerSpec() {
|
||||||
@@ -156,19 +156,13 @@ class OmniPlayer : HybridOmniPlayerSpec() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateSurfaceSize(width: Int, height: Int) {
|
|
||||||
if (width <= 0 || height <= 0) return
|
|
||||||
runOnMainThread {
|
|
||||||
(player as? MpvPlayer)?.updateSurfaceSize(width, height)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override val hasPrev: Boolean get() = currentSource?.metadata?.hasPrev == true
|
override val hasPrev: Boolean get() = currentSource?.metadata?.hasPrev == true
|
||||||
override val hasNext: Boolean get() = currentSource?.metadata?.hasNext == true
|
override val hasNext: Boolean get() = currentSource?.metadata?.hasNext == true
|
||||||
override val status by mainThreadProperty {
|
override val status by mainThreadProperty {
|
||||||
when (player.playbackState) {
|
when (player.playbackState) {
|
||||||
Player.STATE_IDLE,
|
Player.STATE_IDLE,
|
||||||
Player.STATE_ENDED -> PlayerStatus.IDLE
|
Player.STATE_ENDED -> PlayerStatus.IDLE
|
||||||
|
|
||||||
Player.STATE_BUFFERING -> PlayerStatus.LOADING
|
Player.STATE_BUFFERING -> PlayerStatus.LOADING
|
||||||
else -> PlayerStatus.READYTOPLAY
|
else -> PlayerStatus.READYTOPLAY
|
||||||
}
|
}
|
||||||
@@ -208,7 +202,7 @@ class OmniPlayer : HybridOmniPlayerSpec() {
|
|||||||
override val videos by mainThreadProperty { tracksByType(C.TRACK_TYPE_VIDEO) }
|
override val videos by mainThreadProperty { tracksByType(C.TRACK_TYPE_VIDEO) }
|
||||||
override val audios by mainThreadProperty { tracksByType(C.TRACK_TYPE_AUDIO) }
|
override val audios by mainThreadProperty { tracksByType(C.TRACK_TYPE_AUDIO) }
|
||||||
override val subtitles by mainThreadProperty { tracksByType(C.TRACK_TYPE_TEXT) }
|
override val subtitles by mainThreadProperty { tracksByType(C.TRACK_TYPE_TEXT) }
|
||||||
override val rendition: Array<Rendition> get() = emptyArray()
|
override val rendition by mainThreadProperty { getRenditions() }
|
||||||
|
|
||||||
override fun play() {
|
override fun play() {
|
||||||
runOnMainThreadSync { player.play() }
|
runOnMainThreadSync { player.play() }
|
||||||
@@ -234,11 +228,23 @@ class OmniPlayer : HybridOmniPlayerSpec() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun selectVideo(video: Track) {
|
override fun selectVideo(video: Track) {
|
||||||
runOnMainThreadSync { selectTrack(C.TRACK_TYPE_VIDEO, video) }
|
runOnMainThreadSync {
|
||||||
|
player.trackSelectionParameters = player.trackSelectionParameters
|
||||||
|
.buildUpon()
|
||||||
|
.setPreferredVideoLanguage(video.language)
|
||||||
|
.setPreferredVideoLabels(*(video.label?.let { arrayOf(it) } ?: emptyArray()))
|
||||||
|
.build()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun selectAudio(audio: Track) {
|
override fun selectAudio(audio: Track) {
|
||||||
runOnMainThreadSync { selectTrack(C.TRACK_TYPE_AUDIO, audio) }
|
runOnMainThreadSync {
|
||||||
|
player.trackSelectionParameters = player.trackSelectionParameters
|
||||||
|
.buildUpon()
|
||||||
|
.setPreferredAudioLanguage(audio.language)
|
||||||
|
.setPreferredAudioLabels(*(audio.label?.let { arrayOf(it) } ?: emptyArray()))
|
||||||
|
.build()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun selectSubtitle(subtitle: Track?) {
|
override fun selectSubtitle(subtitle: Track?) {
|
||||||
@@ -249,50 +255,78 @@ class OmniPlayer : HybridOmniPlayerSpec() {
|
|||||||
.setTrackTypeDisabled(C.TRACK_TYPE_TEXT, true)
|
.setTrackTypeDisabled(C.TRACK_TYPE_TEXT, true)
|
||||||
.build()
|
.build()
|
||||||
} else {
|
} else {
|
||||||
selectTrack(C.TRACK_TYPE_TEXT, subtitle)
|
player.trackSelectionParameters = player.trackSelectionParameters
|
||||||
|
.buildUpon()
|
||||||
|
.setTrackTypeDisabled(C.TRACK_TYPE_TEXT, false)
|
||||||
|
.setPreferredTextLanguage(subtitle.language)
|
||||||
|
.setPreferredTextLabels(*(subtitle.label?.let { arrayOf(it) } ?: emptyArray()))
|
||||||
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun selectRendition(rendition: Rendition?) {
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun tracksByType(trackType: Int): Array<Track> {
|
private fun tracksByType(trackType: Int): Array<Track> {
|
||||||
val groups = player.currentTracks.groups.filter { it.type == trackType }
|
val groups = player.currentTracks.groups.filter { it.type == trackType }
|
||||||
if (groups.isEmpty()) return emptyArray()
|
if (groups.isEmpty()) return emptyArray()
|
||||||
|
|
||||||
val result = ArrayList<Track>()
|
return groups.map {
|
||||||
for (group in groups) {
|
it.getTrackFormat(0).run {
|
||||||
val mediaGroup = group.mediaTrackGroup
|
Track(
|
||||||
for (i in 0 until group.length) {
|
id = it.mediaTrackGroup.id,
|
||||||
val format = group.getTrackFormat(i)
|
label = this.label,
|
||||||
result.add(
|
language = this.language,
|
||||||
Track(
|
selected = it.isSelected
|
||||||
id = format.id ?: mediaGroup.id,
|
|
||||||
label = format.label,
|
|
||||||
language = format.language,
|
|
||||||
selected = group.isTrackSelected(i)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}.toTypedArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getRenditions(): Array<Rendition> {
|
||||||
|
val group =
|
||||||
|
player.currentTracks.groups.firstOrNull { it.isSelected && it.type == C.TRACK_TYPE_VIDEO }
|
||||||
|
?: return emptyArray()
|
||||||
|
|
||||||
|
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,
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return result.toTypedArray()
|
return result.toTypedArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun selectTrack(trackType: Int, track: Track) {
|
override fun selectRendition(rendition: Rendition?) {
|
||||||
val groups = player.currentTracks.groups.filter { it.type == trackType }
|
runOnMainThreadSync {
|
||||||
for (group in groups) {
|
if (rendition == null) {
|
||||||
for (i in 0 until group.length) {
|
|
||||||
val formatId = group.getTrackFormat(i).id ?: group.mediaTrackGroup.id
|
|
||||||
if (formatId != track.id) continue
|
|
||||||
|
|
||||||
player.trackSelectionParameters = player.trackSelectionParameters
|
player.trackSelectionParameters = player.trackSelectionParameters
|
||||||
.buildUpon()
|
.buildUpon()
|
||||||
.setTrackTypeDisabled(trackType, false)
|
.clearOverridesOfType(C.TRACK_TYPE_VIDEO)
|
||||||
.setOverrideForType(TrackSelectionOverride(group.mediaTrackGroup, i))
|
|
||||||
.build()
|
.build()
|
||||||
return
|
return@runOnMainThreadSync
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val group =
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user