fix(android): include mpv end-file diagnostics

This commit is contained in:
edde746
2026-07-12 08:42:22 +02:00
parent f4ec6ccf20
commit 0135318ded
4 changed files with 159 additions and 2 deletions
@@ -0,0 +1,35 @@
package com.edde746.plezy.mpv
import dev.jdtech.mpv.EndFileReason
import dev.jdtech.mpv.LogLevel
import dev.jdtech.mpv.LogMessage
import dev.jdtech.mpv.MpvEvent
/** Adds the native diagnostic that libmpv-android exposes separately via logFlow. */
internal class MpvEndFileDiagnostics {
private var errorMessage: String? = null
fun onStartFile() {
errorMessage = null
}
fun onLogMessage(message: LogMessage) {
if (message.level == LogLevel.Fatal || message.level == LogLevel.Error) {
errorMessage = message.text.takeIf { it.isNotBlank() }
}
}
fun onEndFile(event: MpvEvent.EndFile): Map<String, Any>? {
val reason = event.reason
if (reason == null) {
errorMessage = null
return null
}
val data = mutableMapOf<String, Any>("reason" to reason.id)
if (reason == EndFileReason.Error) {
errorMessage?.let { data["message"] = it }
}
errorMessage = null
return data
}
}
@@ -73,6 +73,7 @@ class MpvPlayerCore(
@Volatile private var player: MpvPlayer? = null
private var scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
private val endFileDiagnostics = MpvEndFileDiagnostics()
// mpv writes must stay off the main thread but run in submission order:
// setupMpvFallback sets vo/ao/hwdec immediately before the loadfile command,
@@ -184,6 +185,7 @@ class MpvPlayerCore(
try {
disposing = false
endFileDiagnostics.onStartFile()
cachedPaused = true
pausedForSurfaceLoss = false
pendingSurface = null
@@ -361,9 +363,9 @@ class MpvPlayerCore(
p.eventFlow.collect { event ->
when (event) {
is MpvEvent.EndFile -> {
val data = event.reason?.let { mapOf("reason" to it.id) }
delegate?.onEvent("end-file", data)
delegate?.onEvent("end-file", endFileDiagnostics.onEndFile(event))
}
is MpvEvent.StartFile -> endFileDiagnostics.onStartFile()
is MpvEvent.FileLoaded -> delegate?.onEvent("file-loaded", null)
is MpvEvent.PlaybackRestart -> delegate?.onEvent("playback-restart", null)
else -> {}
@@ -397,6 +399,7 @@ class MpvPlayerCore(
private fun collectLogMessages(p: MpvPlayer) {
scope.launch(start = CoroutineStart.UNDISPATCHED) {
p.logFlow.collect { msg ->
endFileDiagnostics.onLogMessage(msg)
emitLog(msg.level.name.lowercase(), msg.prefix, msg.text)
}
}
@@ -1,5 +1,10 @@
package com.edde746.plezy.mpv
import dev.jdtech.mpv.EndFileReason
import dev.jdtech.mpv.LogLevel
import dev.jdtech.mpv.LogMessage
import dev.jdtech.mpv.MpvEvent
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import org.junit.Assert.assertEquals
@@ -37,6 +42,59 @@ class MpvPlayerPluginTest {
assertNull(result.successValue)
}
@Test
fun endFileDiagnosticsPreserveReasonIdAndExposeDependencyErrorLog() {
val diagnostics = MpvEndFileDiagnostics()
diagnostics.onStartFile()
diagnostics.onLogMessage(LogMessage("ffmpeg", LogLevel.Error, "Invalid data found when processing input"))
assertEquals(
mapOf(
"reason" to 4,
"message" to "Invalid data found when processing input"
),
diagnostics.onEndFile(MpvEvent.EndFile(EndFileReason.Error))
)
}
@Test
fun endFileDiagnosticsDoNotAttachStaleOrInventedDetails() {
val diagnostics = MpvEndFileDiagnostics()
diagnostics.onLogMessage(LogMessage("ffmpeg", LogLevel.Error, "old failure"))
diagnostics.onStartFile()
assertEquals(mapOf("reason" to 0), diagnostics.onEndFile(MpvEvent.EndFile(EndFileReason.Eof)))
assertEquals(mapOf("reason" to 4), diagnostics.onEndFile(MpvEvent.EndFile(EndFileReason.Error)))
assertNull(diagnostics.onEndFile(MpvEvent.EndFile(null)))
}
@Test
fun endFileEventChannelPayloadKeepsExistingEnvelopeAndAddsMessage() {
val sink = RecordingEventSink()
val plugin = MpvPlayerPlugin()
plugin.onListen(null, sink)
plugin.onEvent(
"end-file",
mapOf(
"reason" to 4,
"message" to "Failed to open stream"
)
)
assertEquals(
mapOf(
"type" to "event",
"name" to "end-file",
"data" to mapOf(
"reason" to 4,
"message" to "Failed to open stream"
)
),
sink.successValue
)
}
private class RecordingResult : MethodChannel.Result {
var successValue: Any? = null
var errorCode: String? = null
@@ -51,4 +109,16 @@ class MpvPlayerPluginTest {
override fun notImplemented() = Unit
}
private class RecordingEventSink : EventChannel.EventSink {
var successValue: Any? = null
override fun success(event: Any?) {
successValue = event
}
override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) = Unit
override fun endOfStream() = Unit
}
}