diff --git a/tools/chatgui-android/video-tests/build.gradle.kts b/tools/chatgui-android/video-tests/build.gradle.kts index adea0446..7760f8ab 100644 --- a/tools/chatgui-android/video-tests/build.gradle.kts +++ b/tools/chatgui-android/video-tests/build.gradle.kts @@ -17,7 +17,8 @@ kotlin { "com/utun/chat/data/StreamAudioMix.kt", "com/utun/chat/data/StreamReadQueue.kt", "com/utun/chat/data/StreamPlaybackTelemetry.kt", "com/utun/chat/data/StreamCaptureEngine.kt", "com/utun/chat/data/StreamCaptureConfig.kt", "com/utun/chat/data/TelecomCallManager.kt", "com/utun/chat/data/UtunConnection.kt", "com/utun/chat/data/UtunConnectionService.kt", - "com/utun/chat/data/QrScannerSession.kt", "com/google/**") + "com/utun/chat/data/QrScannerSession.kt", "com/utun/chat/data/VideoFilePlayer.kt", + "com/utun/chat/data/VideoFileMetadata.kt", "com/google/**") } } dependencies { diff --git a/tools/chatgui-android/video-tests/src/main/kotlin/android/media/HostFileVideo.kt b/tools/chatgui-android/video-tests/src/main/kotlin/android/media/HostFileVideo.kt new file mode 100644 index 00000000..fbda6a83 --- /dev/null +++ b/tools/chatgui-android/video-tests/src/main/kotlin/android/media/HostFileVideo.kt @@ -0,0 +1,67 @@ +package android.media + +import android.view.Surface + +/** Только управляемая граница MediaPlayer: callbacks и отказы SDK, без декодирования. */ +class MediaPlayer { + companion object { + const val VIDEO_SCALING_MODE_SCALE_TO_FIT = 1 + val created = mutableListOf() + var nextFailures = emptySet() + } + var failures = nextFailures + var released = false + var releases = 0 + var starts = 0 + var pauses = 0 + var seeks = 0 + var surface: Surface? = null + private set + var position = 0 + val currentPosition: Int get() { check("position" !in failures && !released); return position } + val duration: Int get() { check("duration" !in failures); return 10_000 } + val videoWidth = 1280 + val videoHeight = 720 + var preparedCallback: ((MediaPlayer) -> Unit)? = null + var completedCallback: ((MediaPlayer) -> Unit)? = null + var errorCallback: ((MediaPlayer, Int, Int) -> Boolean)? = null + init { check("construct" !in failures); created.add(this) } + fun setOnPreparedListener(callback: (MediaPlayer) -> Unit) { preparedCallback = callback } + fun setOnCompletionListener(callback: (MediaPlayer) -> Unit) { completedCallback = callback } + fun setOnErrorListener(callback: (MediaPlayer, Int, Int) -> Boolean) { errorCallback = callback } + fun setVideoScalingMode(mode: Int) { check("scaling" !in failures) } + fun setDataSource(path: String) { check("source" !in failures) { "MediaPlayer source failed" } } + fun prepareAsync() { check("prepare" !in failures) { "MediaPlayer prepare failed" } } + fun start() { starts++; check(!released && "start" !in failures) { "MediaPlayer start failed" } } + fun pause() { pauses++; check(!released && "pause" !in failures) { "MediaPlayer pause failed" } } + fun seekTo(value: Int) { seeks++; check(!released && "seek" !in failures); position = value } + fun setSurface(value: Surface?) { + check(!released && "surface" !in failures) { "MediaPlayer surface failed" }; surface = value + check("surface after" !in failures) { "MediaPlayer surface failed after effect" } + } + fun release() { + releases++; check("release" !in failures) { "MediaPlayer release failed" }; released = true; surface = null + check("release after" !in failures) { "MediaPlayer release failed after effect" } + } +} + +class MediaMetadataRetriever { + companion object { + const val METADATA_KEY_VIDEO_WIDTH = 18; const val METADATA_KEY_VIDEO_HEIGHT = 19; const val METADATA_KEY_VIDEO_ROTATION = 24 + val created = mutableListOf() + var nextFailures = emptySet() + } + var failures = nextFailures + var released = false + var releases = 0 + var width = "1280"; var height = "720"; var rotation = "90" + init { created.add(this) } + fun setDataSource(path: String) { check("source" !in failures) { "Metadata source failed" } } + fun extractMetadata(key: Int): String? = when (key) { + METADATA_KEY_VIDEO_WIDTH -> width; METADATA_KEY_VIDEO_HEIGHT -> height; METADATA_KEY_VIDEO_ROTATION -> rotation; else -> null + } + fun release() { + releases++; check("release" !in failures) { "Metadata release failed" }; released = true + check("release after" !in failures) { "Metadata release failed after effect" } + } +} diff --git a/tools/chatgui-android/video-tests/src/main/kotlin/com/utun/chat/VideoHostApp.kt b/tools/chatgui-android/video-tests/src/main/kotlin/com/utun/chat/VideoHostApp.kt index a6899333..b27d4cd6 100644 --- a/tools/chatgui-android/video-tests/src/main/kotlin/com/utun/chat/VideoHostApp.kt +++ b/tools/chatgui-android/video-tests/src/main/kotlin/com/utun/chat/VideoHostApp.kt @@ -13,4 +13,5 @@ object R { object string { const val stream_waiting_decoder = 7; const val stream_group_closed = 8; const val chat_service_stopped = 9 const val stream_source_changed = 10; const val stream_member_removed = 11; const val stream_failed = 12 const val stream_decoder_unsupported = 13 + const val video_open_failed = 14; const val video_playback_failed = 15 } }