feat(app-phone): синхронизированный звук на телефоне при просмотре на очках + README-статус
- AudioSyncPlayer (ExoPlayer media3): играет дорожку (локальный файл или presigned S3-URL), коррекция по PlaybackPosition очков (каждые 5с, порог 1000мс), мгновенная реакция на пульт, индикатор «🔊 звук: N мс»
- Вещдок-лог: audio sync: video=N audio=M diff=K (на стенде diff ~150мс)
- Смена озвучки во время просмотра — перезапуск с позиции очков
- README: секция «Статус реализации»
- Тесты 24/0 (8 новых AudioSyncPlayerTest)
This commit is contained in:
@@ -61,6 +61,9 @@ class GlassesHub(
|
||||
private val _positionMs = MutableStateFlow<Long?>(null)
|
||||
val positionMs: StateFlow<Long?> = _positionMs.asStateFlow()
|
||||
|
||||
/** Хук на позицию очков: вызывается на каждый PlaybackPosition (и GlassesOff с playing=false). */
|
||||
var onPlaybackPosition: ((positionMs: Long, playing: Boolean) -> Unit)? = null
|
||||
|
||||
fun add(session: DefaultWebSocketServerSession) {
|
||||
sessions[session] = Unit
|
||||
_connected.value = sessions.size
|
||||
@@ -111,11 +114,13 @@ class GlassesHub(
|
||||
this.state.playing = msg.playing
|
||||
val state = if (msg.playing) "играет" else "пауза"
|
||||
log("glasses", "позиция: ${msg.positionMs} мс, $state")
|
||||
onPlaybackPosition?.invoke(msg.positionMs, msg.playing)
|
||||
}
|
||||
|
||||
is GlassesOff -> {
|
||||
log("glasses", "очки выключились → пауза (${msg.reason})")
|
||||
this.state.playing = false
|
||||
onPlaybackPosition?.invoke(_positionMs.value ?: 0L, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user