mirror of
https://github.com/zoriya/react-native-omni.git
synced 2026-08-16 02:44:51 +00:00
Basic vlc implementation
This commit is contained in:
@@ -1,76 +1,121 @@
|
||||
package dev.zoriya.omni
|
||||
|
||||
import android.net.Uri
|
||||
import com.margelo.nitro.NitroModules
|
||||
import com.margelo.nitro.omni.HybridOmniPlayerPropsSpec
|
||||
import com.margelo.nitro.omni.HybridOmniPlayerSpec
|
||||
import com.margelo.nitro.omni.PlayerStatus
|
||||
import com.margelo.nitro.omni.Rendition
|
||||
import com.margelo.nitro.omni.Track
|
||||
import com.margelo.nitro.omni.Variant_NullType_Rendition
|
||||
import dev.zoriya.omni.utils.deferredObservable
|
||||
import org.videolan.libvlc.LibVLC
|
||||
import org.videolan.libvlc.Media
|
||||
import org.videolan.libvlc.MediaPlayer
|
||||
import org.videolan.libvlc.interfaces.IMedia
|
||||
|
||||
class OmniPlayer(source: HybridOmniPlayerPropsSpec) : HybridOmniPlayerSpec() {
|
||||
override val hasPrev: Boolean
|
||||
get() = TODO("Not yet implemented")
|
||||
override val hasNext: Boolean
|
||||
get() = TODO("Not yet implemented")
|
||||
override val status: PlayerStatus
|
||||
get() = TODO("Not yet implemented")
|
||||
override val isPlaying: Boolean
|
||||
get() = TODO("Not yet implemented")
|
||||
class OmniPlayer() : HybridOmniPlayerSpec() {
|
||||
val vlc = LibVLC(NitroModules.applicationContext ?: throw Error("No Context available!"))
|
||||
val player = MediaPlayer(vlc)
|
||||
|
||||
var source: HybridOmniPlayerPropsSpec by deferredObservable { _, _, new ->
|
||||
val src = new.src.firstOrNull()?.uri ?: return@deferredObservable
|
||||
player.media = Media(vlc, Uri.parse(src))
|
||||
new.startTime?.let { start ->
|
||||
player.time = (start * 1000.0).toLong().coerceAtLeast(0L)
|
||||
}
|
||||
}
|
||||
|
||||
override val hasPrev get() = source.metadata?.hasPrev ?: false
|
||||
override val hasNext get() = source.metadata?.hasNext ?: false
|
||||
override val status
|
||||
get() = when (player.playerState) {
|
||||
IMedia.State.NothingSpecial -> PlayerStatus.IDLE
|
||||
IMedia.State.Opening -> PlayerStatus.LOADING
|
||||
IMedia.State.Playing -> PlayerStatus.READYTOPLAY
|
||||
IMedia.State.Paused -> PlayerStatus.READYTOPLAY
|
||||
IMedia.State.Stopped -> PlayerStatus.IDLE
|
||||
IMedia.State.Ended -> PlayerStatus.IDLE
|
||||
IMedia.State.Error -> PlayerStatus.ERROR
|
||||
else -> PlayerStatus.ERROR
|
||||
}
|
||||
override val isPlaying: Boolean get() = player.isPlaying
|
||||
override var currentTime: Double
|
||||
get() = TODO("Not yet implemented")
|
||||
set(value) {}
|
||||
get() = player.time.coerceAtLeast(0L) / 1000.0
|
||||
set(value) {
|
||||
player.time = (value * 1000.0).toLong().coerceAtLeast(0L)
|
||||
}
|
||||
override val buffered: Double
|
||||
get() = TODO("Not yet implemented")
|
||||
override val duration: Double
|
||||
get() = TODO("Not yet implemented")
|
||||
get() {
|
||||
val total = duration
|
||||
if (total <= 0.0) return 0.0
|
||||
return (total * player.position.toDouble()).coerceIn(0.0, total)
|
||||
}
|
||||
override val duration: Double get() = player.length.coerceAtLeast(0L) / 1000.0
|
||||
override var playbackRate: Double
|
||||
get() = TODO("Not yet implemented")
|
||||
set(value) {}
|
||||
get() = player.rate.toDouble()
|
||||
set(value) {
|
||||
if (value > 0.0) player.rate = value.toFloat()
|
||||
}
|
||||
override var volume: Double
|
||||
get() = TODO("Not yet implemented")
|
||||
set(value) {}
|
||||
override val videos: Array<Track>
|
||||
get() = TODO("Not yet implemented")
|
||||
override val audios: Array<Track>
|
||||
get() = TODO("Not yet implemented")
|
||||
override val subtitles: Array<Track>
|
||||
get() = TODO("Not yet implemented")
|
||||
override val rendition: Array<Rendition>
|
||||
get() = TODO("Not yet implemented")
|
||||
get() = (player.volume.coerceIn(0, 100) / 100.0)
|
||||
set(value) {
|
||||
player.volume = (value.coerceIn(0.0, 1.0) * 100.0).toInt()
|
||||
}
|
||||
override val videos get() = getTracks(IMedia.Track.Type.Video)
|
||||
override val audios get() = getTracks(IMedia.Track.Type.Audio)
|
||||
override val subtitles get() = getTracks(IMedia.Track.Type.Text)
|
||||
|
||||
fun getTracks(type: Int): Array<Track> {
|
||||
val tracks = player.getTracks(type)
|
||||
val selected = player.getSelectedTrack(type)
|
||||
return tracks.map {
|
||||
Track(
|
||||
id = it.id,
|
||||
label = it.name,
|
||||
language = it.language,
|
||||
selected = it.id == selected.id
|
||||
)
|
||||
}.toTypedArray()
|
||||
}
|
||||
|
||||
override val rendition: Array<Rendition> get() = emptyArray()
|
||||
|
||||
override fun play() {
|
||||
TODO("Not yet implemented")
|
||||
player.play()
|
||||
}
|
||||
|
||||
override fun pause() {
|
||||
TODO("Not yet implemented")
|
||||
player.pause()
|
||||
}
|
||||
|
||||
override fun seekBy(offset: Double) {
|
||||
TODO("Not yet implemented")
|
||||
currentTime += offset
|
||||
}
|
||||
|
||||
override fun playPrev() {
|
||||
TODO("Not yet implemented")
|
||||
// App-level action; no default implementation in VLC player.
|
||||
}
|
||||
|
||||
override fun playNext() {
|
||||
TODO("Not yet implemented")
|
||||
// App-level action; no default implementation in VLC player.
|
||||
}
|
||||
|
||||
override fun selectVideo(video: Track) {
|
||||
TODO("Not yet implemented")
|
||||
player.selectTrack(video.id)
|
||||
}
|
||||
|
||||
override fun selectAudio(audio: Track) {
|
||||
TODO("Not yet implemented")
|
||||
player.selectTrack(audio.id)
|
||||
}
|
||||
|
||||
override fun selectSubtitle(subtitle: Track) {
|
||||
TODO("Not yet implemented")
|
||||
override fun selectSubtitle(subtitle: Track?) {
|
||||
when (subtitle) {
|
||||
null -> player.unselectTrackType(IMedia.Track.Type.Text)
|
||||
else -> player.selectTrack(subtitle.id)
|
||||
}
|
||||
}
|
||||
|
||||
override fun selectRendition(rendition: Variant_NullType_Rendition?) {
|
||||
TODO("Not yet implemented")
|
||||
override fun selectRendition(rendition: Rendition?) {
|
||||
// Not supported by libVLC MediaPlayer track APIs.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import com.margelo.nitro.omni.HybridOmniPlayerSpec
|
||||
|
||||
class OmniPlayerFactory(val context: ThemedReactContext): HybridOmniPlayerFactorySpec() {
|
||||
override fun createPlayer(props: HybridOmniPlayerPropsSpec): HybridOmniPlayerSpec {
|
||||
return OmniPlayer(props)
|
||||
return OmniPlayer().apply {
|
||||
source = props
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package dev.zoriya.omni.utils
|
||||
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
inline fun <T : Any> deferredObservable(
|
||||
crossinline onChange: (thisRef: Any?, oldValue: T?, newValue: T) -> Unit
|
||||
): ReadWriteProperty<Any?, T> =
|
||||
object : ReadWriteProperty<Any?, T> {
|
||||
private var value: T? = null
|
||||
|
||||
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
||||
return value ?: throw IllegalStateException("Property ${property.name} should be initialized before get.")
|
||||
}
|
||||
|
||||
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
||||
val old = this.value
|
||||
this.value = value
|
||||
onChange(old, value)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user