feat(app-glasses): жесты RayNeo SDK (TempleAction) + отключение звуков трекпада
Перенос из pair-view (проверено на железе): RayNeoARSDK V0.1.3 (aar в libs/, MercurySDK.init в GlassesApp), MainActivity → BaseEventActivity, templeActionViewModel.state → команды (Click=пауза/плей, SlideForward/ Backward=±30с), dispatchTouchEvent→onTouchEvent + toggleSoundEffect(0..3, false) — системные щелчки трекпада отключены. Фиксы по ходу (железо): - applyMediaCommand(msg, onDone) — sendPlaybackPositionNow после seekTo (иначе телефон получал позицию ДО seek) - догонка seekTo через 1с на телефоне (первый seekTo в ogg неточен) - playbackPosition: isPlaying → playWhenReady — ложное playing=false при буферизации после seekTo паузило звук на телефоне (~5с «пропажи»); pauseIfPlaying тоже по playWhenReady Тесты: glasses 59+5, phone 71. Железо: клик пауза/плей ✓, свайпы ±30с ✓, звук при seek не пропадает ✓ (подтверждено пользователем)
This commit is contained in:
@@ -115,6 +115,11 @@ class AudioSyncPlayer(private val context: Context) {
|
||||
private var player: ExoPlayer? = null
|
||||
private var ticker: Job? = null
|
||||
|
||||
/** Позиция очков из последнего sync (для догонки после неточного seekTo). */
|
||||
private var lastVideoPositionMs = 0L
|
||||
/** IsPlaying очков из последнего sync. */
|
||||
private var lastVideoPlaying = false
|
||||
|
||||
private val _positionMs = MutableStateFlow(0L)
|
||||
/** Текущая позиция аудио (для индикатора «🔊 звук: N мс»). Обновляется каждые 500 мс. */
|
||||
val positionMs: StateFlow<Long> = _positionMs.asStateFlow()
|
||||
@@ -151,9 +156,24 @@ class AudioSyncPlayer(private val context: Context) {
|
||||
fun sync(positionMs: Long, isPlaying: Boolean) {
|
||||
main.post {
|
||||
val p = player ?: return@post
|
||||
lastVideoPositionMs = positionMs
|
||||
lastVideoPlaying = isPlaying
|
||||
val audioPos = p.currentPosition
|
||||
val decision = decideSync(audioPos, positionMs, p.isPlaying, isPlaying)
|
||||
decision.seekToMs?.let { p.seekTo(it) }
|
||||
decision.seekToMs?.let {
|
||||
p.seekTo(it)
|
||||
lastVideoPositionMs = it
|
||||
// Догонка через 1с: первый seekTo в ogg приблизительный (недолёт ~2с),
|
||||
// второй seekTo точен — делаем его сразу, не дожидаясь следующего sync (5с).
|
||||
main.postDelayed({
|
||||
val pp = player ?: return@postDelayed
|
||||
val target = lastVideoPositionMs + 1_000 // очки ушли вперёд за секунду
|
||||
if (abs(pp.currentPosition - target) > 500) {
|
||||
pp.seekTo(target)
|
||||
log("audio sync:", "догонка seekTo → $target (было ${pp.currentPosition})")
|
||||
}
|
||||
}, 1_000)
|
||||
}
|
||||
decision.playing?.let { if (it) p.play() else p.pause() }
|
||||
log("audio sync:", "video=$positionMs мс audio=$audioPos мс diff=${abs(audioPos - positionMs)}")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user