Skip to content

release: v0.4.7 — Avanços da Fase 0.4 e Versionamento CI/CD - #10

Merged
BGLuis merged 37 commits into
mainfrom
develop
Sep 16, 2026
Merged

BGLuis merged 37 commits into
mainfrom
develop

Conversation

@BGLuis

@BGLuis BGLuis commented Sep 16, 2026

Copy link
Copy Markdown
Owner

Description

Este Pull Request integra os avanços de desenvolvimento da branch develop para a main, consolidando o marco v0.4.7 (Fase 0.4 - Tarefa T4.7 de downloads e integração com biblioteca) e a sincronização do pipeline de release do CI/CD.

Principais Destaques:

  • Sincronização de Versão e CI/CD (v0.4.7):
    • Criação de version.properties como fonte única da verdade para versão (versionName=0.4.7, versionCode=470).
    • Atualização do app/build.gradle.kts e scripts/build.sh para carregar e suportar overrides de versão.
    • Atualização do workflow .github/workflows/release.yml para nomear releases como v0.4.7-build.X e gerar APK com a nomenclatura correta (tucaVR-v0.4.7-build.X.apk).
  • Fase 0.4 (Advanced):
    • Seção 4: Download offline de vídeos e integração automática com a biblioteca local (T4.1 a T4.7).
    • Seção 3: Suporte ao protocolo WebDAV.
    • Seção 2: Suporte a streaming MPEG-DASH.
    • Seção 6: Projeções avançadas (Cubemap 3x2 e EAC).
    • Qualidade adaptativa 8K e foveated rendering.
  • Renderização e Áudio:
    • Pipeline Vulkan padrão (vr_player_app_vulkan.cpp), correção da matriz YCbCr e desacoplamento de decode/apresentação.
    • Legendas ASS/PGS renderizadas em Vulkan.
    • Áudio espacial (Ambisonics / HRTF) e surround sound.
    • Hand tracking OpenXR com gestos e raycasting.
  • Telemetria e Estabilidade:
    • Métricas F0 a F8 e HUD de telemetria expandido com exportação CSV.
    • Buffer gate logic, retry backoff com jitter para I/O de rede.

Type of change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 🛠️ Technical refactor / Code improvement
  • 📝 Documentation update
  • 🚀 Performance optimization

Affected layers

  • 🟣 Kotlin (app/) — app shell, UI panels, credentials, history, i18n
  • 🔵 C++ (native/) — OpenXR session, Vulkan/GLES render loop, controller input
  • 🦀 Rust (rust/) — demux, decode, audio, network protocols
  • 🔧 Build / CI / scripts

How has this been tested?

  • Testes unitários Rust (cargo test -p protocols -p media-logic): 79 testes passando
  • Testes unitários nativos C++ no host (./scripts/test-native-host.sh): 5 binários passando
  • Testes unitários Kotlin JVM (./gradlew testDebugUnitTest): 25 tarefas executadas com sucesso
  • Compilação e geração de BuildConfig.VERSION_NAME ("0.4.7") validada no Gradle

Checklist:

  • My code follows the project's style guidelines.
  • I have performed a self-review of my own code.
  • I have added new tests that prove my fix is effective or that my feature works.
  • Kotlin never calls Rust directly — the Kotlin → JNI → C++ → C ABI → Rust path is preserved (ADR-002).
  • Screen mode enum synchronized across rust/bridge, native/include/screen_mode.h and ScreenFormatCatalog.kt.
  • No credential is stored or logged in plain text.

BGLuis and others added 30 commits August 29, 2026 03:53
Implementa todos os itens de alta prioridade dos relatórios PHASE-0.3-03 e
PHASE-0.3-04 de áudio espacial para o tucaVR (Meta Quest 3).

## Rust / media-logic

### Detecção de Ambisonics (T3.1)
- Adiciona from_channel_count_tags_and_ordering() em AudioChannelLayout:
  propaga ChannelOrdering/Normalization detectados pelos parsers do container.
- Corrige bug crítico: 4 canais sem tag agora retorna Unknown(4) em vez de
  AmbisonicsFoa (eliminava falso-positivo em conteúdo quadrafônico).
- Comentário enganoso 'FOA/SOA' em ambisonics.rs corrigido.

### Detecção estrutural de metadados (audio_decoder.rs)
- detect_from_sa3d_box(): parseia a box SA3D de átomos MP4/MOV.
  Byte ambisonic_type=0 → FuMa, 1 → ACN. Desbloqueia FuMa real.
- detect_from_mkv_ambisonics_tag(): parseia o codec private MKV com
  marcador AMBI para detecção de ordering nos containers Matroska.
- detect_from_tags(): heurística de texto existente preservada como
  primeira camada (compatível com tags do YouTube/GoPro).

### Modo screen-locked — world-locked (T4.4)
- GLOBAL_AUDIO_SCREEN_LOCKED + GLOBAL_SCREEN_ROT_* em mod.rs.
- compute_screen_locked_orientation(head, screen): fórmula
  screen.conjugate() * head — speakers seguem o painel de vídeo.
- set_global_screen_orientation() / get_global_screen_orientation().
- surround.rs::process_block: lê GLOBAL_AUDIO_SCREEN_LOCKED por bloco;
  quando ativo, usa orientação relativa à tela em vez do espaço absoluto.

### Bridge C-ABI (bridge/lib.rs)
- set_audio_screen_locked / get_audio_screen_locked
- set_screen_orientation (para o render loop atualizar a pose do quad)

## Kotlin / Android

### FeatureFlags.kt
- SPATIAL_SCREEN_LOCKED flag (persistida em SharedPreferences booleana).
- getSpatialAudioMode() / setSpatialAudioMode(): persiste modo 0/1/2
  como Int em vez do booleano anterior.

### SettingsScreen.kt (T4.5)
- Remove buildFlagRow de SPATIAL_AUDIO (toggle booleano 0/1).
- Adiciona buildSpatialAudioModeRow(): seletor de 3 VoidFilterChips
  (Desligado / Binaural / Downmix) — mesmo padrão do buildUpscalingRow().
- Adiciona checkbox Screen-locked condicional: visível apenas quando head
  tracking estiver ativo. Referências de view guardadas para atualizar
  visibilidade dinamicamente no callback de head tracking.

### VRActivity.kt
- onCreate: usa getSpatialAudioMode() (Int) em vez de booleano.
- onCreate: inicializa nativeSetAudioScreenLocked() da preferência salva.
- onThermalStateChanged (T4.5 / Seção 11): MODERATE+ → SimpleDownmix
  automático; retorno a NORMAL → restaura modo preferido do usuário.
- Adiciona external fun nativeSetAudioScreenLocked(locked: Boolean).

### C++ JNI (vr_player_jni_vulkan.cpp, vr_player_app.cpp)
- Java_com_tucavr_VRActivity_nativeSetAudioScreenLocked nos backends
  Vulkan e GLES. Declarações extern adicionadas nos blocos respectivos.

### Strings (EN + PT-BR)
- settings_spatial_audio_description (atualizada).
- settings_spatial_audio_mode_off / _binaural / _downmix.
- settings_spatial_screen_locked_label / _description.

## Testes (17 testes passando)

Novos testes adicionados:
- test_7_1_virtualizer_head_rotation (surround.rs): cobre 8 canais.
- test_lfe_does_not_leak_above_120hz (surround.rs): Butterworth 120 Hz.
- test_simple_downmix_mode_produces_output (mod.rs): modo 2 acessível.
- test_acn_and_fuma_produce_different_outputs (mod.rs): regressão FuMa.
- test_four_channels_without_tag_is_unknown (mod.rs): falso-positivo.
- test_four_channels_with_ambisonics_tag_is_foa (mod.rs).
- test_fuma_ordering_propagated (mod.rs).

cargo test -p media-logic spatial_audio: 17/17 OK
./gradlew testDebugUnitTest: BUILD SUCCESSFUL
cargo clippy -p media-logic -- -D warnings: OK (zero warnings)
…XR_FB_passthrough)

Implementa passthrough / mixed reality no caminho Vulkan, conforme
docs/reports/PHASE-0.3-02-PASSTHROUGH.md (T2.1, T2.2, T2.3 + detecção de
capacidade). T2.4 (slider de opacidade) e T2.5 (reposicionar a tela)
ficam para tasks separadas.

Fluxo (Kotlin → JNI/C++ → bridge Rust, padrão do projeto):
- Manifest: uses-feature com.oculus.feature.PASSTHROUGH (required=false) +
  uses-permission com.oculus.permission.USE_SCENE.
- bridge: atomics PASSTHROUGH_ENABLED / PASSTHROUGH_SUPPORTED com
  get/set_passthrough_* (mesmo padrão de foveation).
- C++ (vr_player_app_vulkan.cpp):
  - CreateXrInstance detecta XR_FB_passthrough e propaga a capacidade pro
    Kotlin via set_passthrough_supported.
  - SetupPassthrough cria XrPassthroughFB + layer RECONSTRUCTION (pausados).
  - UpdatePassthrough (polling ~2 Hz no RenderFrame) sincroniza resume/pause
    com o toggle; não usa OXR() (retry em vez de abort numa troca de foco).
  - xrEndFrame: layers[5]→[6], XrCompositionLayerPassthroughFB no índice 0,
    XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT no projection layer,
    clear do eye buffer com alpha 0 (PassthroughEnvAlpha) quando ativo.
    Espelha o sample XrSceneSharing da Meta.
  - DestroyPassthrough antes de xrDestroySession.
  - Shaders video/stereo: alpha do vídeo forçado a 1.0 (vídeo é opaco).
- Kotlin: FeatureFlags.PASSTHROUGH, nativeSetPassthroughEnabled /
  nativeIsPassthroughSupported, botão em VRControlsPresentation sai de
  DISABLED só quando suportado (ON = VoidButtonStyle.ACTIVE).
- GLES (vr_player_app.cpp): wrappers JNI stub p/ simetria de ABI; feature
  é Vulkan-only, botão continua desabilitado nesse caminho.

Correção incidental (build quebrado no develop, commit 74c04da):
audio_decoder.rs usava decoder.extradata(), que não existe em
ffmpeg-next 9; lê do AVCodecParameters cru (padrão de get_video_extradata).

Verificação: build unificado OK, cargo test -p protocols -p media-logic
(189 testes) OK, clippy OK, APK instalado no Quest 3. Falta validação
visual no headset (toggle, sem retângulo preto, FPS, ida-e-volta).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015aGGCZ54R3rPuPR9yKxHX7
…utidas

Parte Rust da Seção 7 (T7.1, T7.3, T7.5, T7.6). O render estilizado no
Vulkan (T7.2 ASS, T7.4 PGS) fica pendente — precisa do Quest 3.

- T7.1: media-logic/subtitle_ass.rs — parser ASS/SSA no escopo v0.3
  ([Script Info]/[V4+ Styles]/[V4 Styles] legado/[Events]; cores
  &HAABBGGRR; override \pos \an \a \c \1c \fs \fn \b \i \u \fad \N \n \h;
  tags fora de escopo removidas, nunca vazadas). Expõe AssSubtitle (spans
  + pos + alignment + fade, para o render) e to_subtitle_entries() (texto
  puro, já usável no caminho de render de texto atual). Inclui
  ass_document_from_mkv_packets p/ remontar a partir de pacotes de container.
- T7.3: media-logic/subtitle_pgs.rs — parser PGS: split de segmentos
  PCS/WDS/PDS/ODS/END (framing .sup e cru), remontagem de ODS fragmentado,
  descompressão RLE, paleta YCrCb+alfa → RGBA (BT.601), composição em
  bounding box e resolução de timing. Saída PgsSubtitle pronta p/ textura.
- T7.5: corrige o no-op silencioso de load_subtitle_track — agora há ramo
  de faixa embutida via subtitle_loader::load_embedded_subtitle (SubRip,
  TEXT, WebVTT, MOV_TEXT, ASS/SSA). Bitmap embutido (PGS/DVD) retorna erro
  explícito em vez de faixa vazia.
- T7.6: media_logic::subtitle::match_subtitle_language + normalização
  ISO 639-2→639-1; PlaybackController auto-seleciona pelo idioma do sistema
  quando o usuário não escolheu. Plumbing: set_preferred_subtitle_language
  (Rust ABI) → nativeSetPreferredSubtitleLanguage (JNI) → startSession()
  passa Locale.getDefault().
- Sidecar .ass/.ssa reconhecido em subtitle_loader (extensão e conteúdo).

Testes: cargo test -p media-logic subtitle — 27 casos novos, verdes.
clippy -p protocols -p media-logic -D warnings limpo.
As mudanças em rust/core e native/ seguem os padrões existentes mas não
compilam no host (restrição ndk-sys/oboe-sys) — não verificadas.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HH975MiXdQHnNf6rvWXSN1
…ng (Fase 0.4)

- Cria QualityController em Rust com histerese assimétrica (5 níveis: Ultra, High, Medium, Low, Emergency).
- Unifica tabela de upscaling via FFI Rust, eliminando lógica C++ duplicada.
- Integra controle dinâmico de foveação (XR_FB_foveation), render scale e taxa de atualização (90/72Hz) no render loop Vulkan.
- Configura max-input-size de 4MB e prioridade realtime no MediaCodec para decodificação 8K robusta.
- Adiciona seletor granular de FFR na UI (Off/Low/Med/High/Auto) e badge de qualidade adaptativa no painel de controles.
- Enriquece telemetria de diagnóstico com quality_level e quality_reason.
… grab 3D da tela (Fase 0.3 Seção 2)

- T2.4: Carrega xrPassthroughLayerSetStyleFB no compositor Vulkan e adiciona PassthroughSettingsModal no 3º quad frontal com slider de opacidade (0-100%) e toggle de Edge Rendering.
- T2.5: Implementa reposicionamento espacial 3D com gesto Grab & Drag (Grip controller sobre a tela) e fixação em STAGE reference space.
- Integração de toggle rápido na barra de controles (VRControlsPresentation) com suporte a long-press e atalho na SettingsScreen.
- Sincronização atômica de estilo no bridge Rust e novos wrappers JNI.
- Otimização para vídeos 360° esféricos com pausa automática da camada de passthrough para economia de GPU.
…0.4 Secao 6)

- Adiciona 5 novos modos ao contrato ScreenMode (10..14): Cubemap 3x2, Cubemap 6x1, EAC 3x2, Cubemap 3x2 SBS e EAC 3x2 SBS
- Implementa shaders Vulkan stereo_cubemap.vert e stereo_cubemap.frag com transformacao EAC arctan, anti-seam clamp e layouts 3x2/6x1/Cross
- Integra pipeline stereoCubemapPipeline em vr_player_app_vulkan.cpp com compartilhamento de layout e buffers YCbCr
- Implementa deteccao automatica de projecoes por metadados de container e heuristicas de aspect ratio no Rust
- Adiciona aba 'Cubemap' com icones vetoriais e i18n (EN, PT-BR, ES) no modal de formato e catalogo do Kotlin
- Atualiza testes unitarios em C++, Rust e Kotlin garantindo cobertura e paridade de contrato
- Generaliza AdaptiveBitrateManager com o trait BitrateVariant em rust/protocols/src/hls/abr.rs
- Implementa parser de manifesto MPD em rust/protocols/src/dash/manifest.rs (SegmentTemplate, SegmentBase, duracoes ISO-8601 e resolucao de templates)
- Implementa DashStreamSource em rust/protocols/src/dash/stream.rs com download e cache de initialization segment, streaming sequencial e seek por timestamp
- Roteia streams .mpd e dash:// atraves de DashStreamSource em rust/core/src/demuxer.rs
- Adiciona export C-ABI dash_probe_representations em rust/bridge/src/lib.rs
- Implementa ponte JNI nativeDashProbeRepresentations para backends Vulkan e OpenGL ES em native/
- Atualiza camada Android Kotlin com declaracao JNI em VRActivity, validacao de scheme dash:// e reconhecimento da extensao mpd em DirectoryLister
- Adiciona testes unitarios abrangentes em Rust e Kotlin com 100% de sucesso
- Implementa cliente WebDAV em rust/protocols/src/webdav/ (WebdavTarget, WebdavFileSource com RangeSource paralelo e parser streaming XML quick-xml para PROPFIND Depth: 1)
- Adiciona encoding RFC 3986 segmento a segmento com percent-encoding e redigir seguro de credenciais
- Conecta WebdavFileSource com PrefetchReader e cache de blocos em rust/core/src/demuxer.rs
- Exporta funcoes C-ABI start_webdav_playback e webdav_list_directory em rust/bridge/src/lib.rs
- Adiciona funcoes JNI nativePlayWebdav e nativeWebdavListDirectory para Vulkan e OpenGL ES em native/
- Implementa NetworkWebdavScreen com suporte a HTTPS, certificados auto-assinados, busca, ordenacao e filtros no Void Design System
- Adiciona 8a aba WebDAV no NetworkHomeScreen e orquestracao no VRPresentation
- Integra com persistencia Room, Keystore (ServerCredentialStore), historico de reproducao imune a mudancas de IP e suporte a Playlists
- Mantem paridade estrita de strings e placeholders nos 3 idiomas (en, pt-BR, es)
- Adiciona testes unitarios em Rust e Kotlin com 100% de aprovacao
…e 0.4 Secao 4)

- Implementa motor nativo de download com RangeSource e resume em rust/protocols/src/download/ (SMB, SFTP, FTP, NFS, WebDAV, HTTP/HTTPS)
- Adiciona controle de concorrencia (maximo 2 downloads ativos) e auto-pausa automatica durante streaming ativo
- Exporta funcoes C-ABI em rust/bridge/src/lib.rs e bindings JNI em native/ com paridade entre Vulkan e GLES
- Atualiza schema Room de v3 para v4 com MIGRATION_3_4, entidade Download e DownloadDao, removendo fallbackToDestructiveMigration
- Implementa ForegroundService (DownloadService com tipo dataSync) e permissoes no AndroidManifest
- Adiciona DiskSpaceManager com buffer de seguranca preventivo de 2 GB e alertas de espaco em disco
- Implementa DownloadsScreen no Void UI, botao de download em FileDetailScreen e atalho em HomeScreen
- Garante paridade estrita de strings e placeholders posicionais nos 3 idiomas (EN, PT-BR, ES)
- Adiciona testes unitarios em Rust e Kotlin com 100% de aprovacao
… pos-implementacao

Corrige os 10 achados recomendados (R-01 a R-10) de
docs/reports/PHASE-0.4-08-VERIFICACAO-PROFUNDA.md, complementando os dois fixes
ja aplicados (cubemapLayout invertido e path traversal no download):

- R-01: SSRF em DASH — resolve_dash_url restringe segmentos/BaseURL a mesma
  origem do MPD; redirect::Policy::none() fecha o contorno via redirect 3xx.
- R-02/R-03: DASH SegmentBase agora baixa segmentos de midia em blocos via
  Range (antes so baixava o segmento de inicializacao) e seek aproximado
  passa a funcionar para essas representacoes.
- R-04: novos testes de integracao rust/protocols/tests/{dash,webdav}_integration.rs
  contra servidores Docker reais (bytemark/webdav e MPDs gerados por ffmpeg),
  novo servico webdav-test em docker/network-tests/.
- R-05: testes de migracao Room (AppDatabaseMigrationTest) via sqlite-jdbc
  puro-JVM, sem Robolectric — SQL das migrations extraido para constantes
  testaveis em AppDatabase.
- R-06: Download.serverId agora preenchido a partir da origem de rede;
  binding JNI de auto-pausa morto documentado.
- R-07: contadores de draw call/triangulo instrumentados nos 12 pontos de
  desenho Vulkan, propagados ate o HUD de debug e o CSV de telemetria.
- R-08: CSV de telemetria ganha as colunas quality_level/quality_reason.
- R-09: Toast nao-intrusivo para sobrecarga de GPU/frame pacing (antes so
  havia aviso para transicoes termicas).
- R-10: referencias obsoletas a modeLabelResIds corrigidas, entrada T5.1
  duplicada removida, indice de docs/reports/README.md atualizado.

Verificado com build completo (Rust cross-compilado + NDK/CMake + Gradle),
257 testes Rust de host + clippy -D warnings limpo, 231 testes Kotlin, e uma
rodada real de scripts/test-network-protocols.sh contra containers Docker
(DASH e WebDAV incluidos pela primeira vez).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDv47YownvR5s2UKbUZP2D
…izacao (P-01 a P-05)

Implementa o backlog priorizado em docs/reports/TRAVAMENTOS-POS-REINICIO-DO-HEADSET.md,
confirmado com telemetria real de producao e validacao em headset conectado:

- P-01/P-06: le a taxa real de atualizacao via xrEnumerateDisplayRefreshRatesFB/
  xrGetDisplayRefreshRateFB em vez de assumir o valor pedido; trata
  XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB; HUD e smoothedFps passam a refletir
  a taxa confirmada, nao mais 90 fixo.
- P-04: remove o pedido de taxa duplicado do bloco termico — RequestAndConfirmDisplayRefreshRate
  vira o unico ponto que escreve state.displayRefreshRate.
- P-02/P-03: acumulador de 1Hz em torno da avaliacao do QualityController (antes rodava a
  ~90Hz); regra de dropped-frames ganha contador de 2 amostras consecutivas, igual as regras
  de GPU/pacing, corrigindo a trava permanente em nivel baixo observada em sessoes reais.
- P-05: habilita XR_KHR_android_thread_settings e registra a thread principal e as 3 threads
  Rust do pipeline (demux/video/audio) como criticas ao runtime XR.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDv47YownvR5s2UKbUZP2D
…l de controles

Corrige NullPointerException ao abrir o modal de playlist (PlaylistModal
chamava updateModeText() antes de btnMode terminar de ser atribuido —
leak do `this` durante a propria inicializacao).

Reorganiza VRControlsPresentation para reduzir o amontoado de botoes na
barra inferior: move Formato de Tela/Inverter Olhos/Passthrough para o
cabecalho (ajustados no maximo uma vez por video, nao a cada segundo como
play/seek), remove a engrenagem e os placeholders de Volume/Velocidade
sem nenhuma acao ligada, reduz a margem excessiva ao redor do play/pause
e distribui Playlist/Legendas/Audio/Stats nas laterais do bloco de
reproducao. Corrige tambem a centralizacao do badge de bateria/relogio no
cabecalho, que quebrou ao mover botoes pra la, trocando espacadores fixos
por duas zonas de mesmo peso.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NRZvyVVEKfagyCNkVSa6pM
…tria e graficos

Contrato unico de campos e schema_version versionado (F0); frescor por grupo
e contador de stall de video D-02 (F1); corrige D-01 (malha de qualidade
adaptativa travada em MEDIUM apos degradar) e D-03 (senha de servidor de
rede vazando em claro no crash report) (F2); XR_META_performance_metrics
com os 10 contadores corretos e habilitacao do sistema de metricas (F3);
contadores na origem — underrun de audio, fila de audio, erros de
decode/demux, falhas de rede, fases do load, error ring buffer exposto
via FFI (F4); bottleneck_stage + os 5 graficos do painel via VoidChart.kt,
primeiro View customizado do projeto, e os 7 campos ja coletados que nunca
apareciam na UI (F5); log de eventos por sessao + scripts/plot-session.py
pra regenerar os graficos no PC sem headset (F6); docs/DEBUGGING.md
reescrito (F7); ApplicationExitInfo, thermal headroom continuo e sessao
ADPF (F8).

Ver docs/reports/TRIAGEM-TELEMETRIA-E-GRAFICOS.md para o relatorio
completo. Verificado via: 260 testes Kotlin + suite Rust host
(media-logic/protocols) passando, Rust cross-compilado via NDK real
(cargo ndk) para core/bridge/audio, C++ compilado e linkado contra os
headers OpenXR reais, e APK completo montado com sucesso
(assembleDebug). Legibilidade dos graficos e comportamento em hardware
real (XR_META_performance_metrics, ADPF, underrun de audio) permanecem
nao verificados sem um Quest 3 conectado.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NRZvyVVEKfagyCNkVSa6pM
msSinceLastVideoFrame acumulava mesmo com o playback pausado, entao
qualquer pausa > kVideoStallThresholdMs (500ms) virava um falso
positivo em videoStallCount/video_status ao retomar, indistinguivel
de travamento real de decode/rede. Guard com get_playback_is_playing()
nos dois back-ends (GLES e Vulkan).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NRZvyVVEKfagyCNkVSa6pM
BGLuis and others added 7 commits September 13, 2026 14:56
…playback

Binario de linha de comando (cargo run -p protocols --bin speed_test)
que abre uma conexao real (SMB/SFTP/FTP/NFS/WebDAV/HTTP(S)) usando o
mesmo default_source_opener/RangeSource do Download Manager em producao,
e le o arquivo sequencialmente medindo MB/s — sem decode/render/OpenXR
no caminho.

Objetivo: permitir testar os dois lados do gargalo visto nas sessoes de
telemetria com stalls longos via SFTP (10.10.10.44:2022) — se o
throughput bruto medido aqui tambem cair/travar, o problema e rede/
servidor; se ficar estavel enquanto o playback no headset trava, o
gargalo esta em outro estagio do pipeline do app.

Roda em qualquer host (protocols nao tem dependencia de NDK/Android).
Testado manualmente contra um servidor HTTP local com suporte a Range.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NRZvyVVEKfagyCNkVSa6pM
… leitura

Achado via telemetria (docs/reports/TRIAGEM-TELEMETRIA-E-GRAFICOS.md) e
confirmado com rust/protocols/src/bin/speed_test.rs: travamentos de
dezenas de segundos (54s, 63s) durante playback via SFTP nao eram causados
pela rede em si (leitura sequencial pura nunca ficou parada por mais de
alguns segundos) — eram causados pela thread de demux, que reiniciava do
byte 0 do arquivo em QUALQUER erro de leitura, mesmo um soluco transitorio
de rede plenamente normal, sem nenhum backoff. Se a rede continuasse ruim
por mais um instante, o proximo read_packet() falhava do mesmo jeito,
reiniciava do zero de novo, em loop, cada volta custando ate ~20s so no
retry interno do cliente SFTP.

Alem do freeze, isso fazia o video voltar pro comeco silenciosamente: o
seek(0,..) direto no AVFormatContext nao passava pelo canal
DemuxCommand::SeekTo, entao nem seek_latency_ms nem a epoch da sessao
refletiam o que tinha acontecido - invisivel na telemetria.

Corrige tentando retomar perto da ULTIMA posicao de video com sucesso
(last_good_pos_sec, atualizada a cada pacote de video lido) por ate
READ_ERROR_MAX_RESUME_ATTEMPTS (3) tentativas, com um backoff curto entre
elas, so caindo pro seek-pro-inicio como ultimo recurso. Cada tentativa
agora tambem incrementa a epoch da sessao, entao video/audio sabem que
houve uma descontinuidade.

Verificado: compila limpo (cargo ndk check/clippy -p core, aarch64-linux-android
- core nao roda em host, ver CLAUDE.md), build completo via scripts/build.sh,
instalado no Quest 3 real. NAO verificado ainda: comportamento sob um
travamento de rede real no headset (precisa reproduzir em condicao de
rede ruim de novo para confirmar na telemetria).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NRZvyVVEKfagyCNkVSa6pM
Adiciona ACTION_DEBUG_PLAY_SFTP ao receiver de debug ja existente
(registerDebugReceiverIfDebuggable, mesmo padrao de SET_SCREEN_MODE/
SET_THERMAL_STATUS - so build debuggable, FLAG_DEBUGGABLE). O mecanismo
de auto-play por Intent (video_path/EXTRA_AUTO_PLAY_PATH, ver
docs/DEBUGGING.md secao 2 e scripts/soak-test.sh) so cobre arquivo local
(playFile -> PlaybackSource.LocalFile); nao havia como automatizar via
adb um teste especifico contra um servidor de rede real (o cenario dos
stalls investigados em docs/reports/TRIAGEM-TELEMETRIA-E-GRAFICOS.md)
sem navegar a UI VR manualmente.

Uso:
  adb shell am broadcast -a com.tucavr.debug.PLAY_SFTP \
    --es host <host> --ei port <porta> \
    --es user <usuario> --es password <senha> \
    --es path <caminho remoto>

Verificado ao vivo contra um servidor SFTP real: conecta, autentica, abre
o arquivo, decoder/audio ficam prontos e o video comeca a bufferizar,
tudo via adb, sem tocar no headset. Achado no processo (nao uma limitacao
deste commit, e sim do proprio device): sem o headset em uso, o Quest
periodicamente suspende o loop de render/composicao mesmo com o processo
vivo e a Activity "resumed" no ActivityManager - a telemetria e a
amostragem de rede continuam acontecendo, so de forma bem mais esparsa/
em rajadas do que com o headset realmente em uso. Util pra testar rapido
o caminho de conexao/autenticacao/carregamento sem o headset; pra um soak
test longo o suficiente pra pegar um stall de rede raro, ainda e melhor
com o headset ativo.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NRZvyVVEKfagyCNkVSa6pM
… operations

- Added `buffer_gate.rs` to manage buffer targets and gate states for media playback.
- Introduced `retry_backoff.rs` for exponential backoff with jitter to handle retry attempts in network operations.
- Updated `lib.rs` to include new modules for buffer gate and retry backoff.
- Modified FTP, HTTP, and SMB protocols to utilize the new retry backoff logic for chunk reading.
- Ensured that retry attempts are logged and managed with appropriate backoff delays to prevent thundering herd problems.
Vulkan: VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601 -> YCBCR_709
(CreateYcbcrAndVideoPipeline). Era a unica conversao de cor de todo o
pipeline de video Vulkan e estava usando a matriz de SD para conteudo
HD/4K/8K real, deslocando cor (sobretudo tons de pele/vermelhos) em
todo video ja em producao.

rust/core: HwDecoder ganha feed_input/try_dequeue_output/release_output,
separando "enfileirar pacote" de "drenar e liberar saida" (antes fundidos
em decode_packet). O loop de video (playback.rs) mantem os frames
decodificados-mas-nao-liberados numa fila local (VecDeque<OutputBuffer>,
sem copia, dentro do proprio pool de buffers do MediaCodec) e espera a
hora de apresentar em fatias curtas (10ms) em vez de um sleep unico —
o decode do proximo pacote deixa de ficar bloqueado atras da espera de
apresentacao do frame anterior. media_logic::frame_timing isola a
decisao pura (pouso de seek / esperar / mostrar / descartar), testavel
via cargo test -p media-logic.

T-HDR: media_logic::color mapeia AVColorTransferCharacteristic (PQ/HLG)
pra uma deteccao de HDR simples, propagada via get_video_is_hdr() no
bridge. MediaCodec recebe color-standard/range/transfer explicitos
(SDR por padrao, BT.2020+PQ/HLG quando detectado). Os tres shaders de
video Vulkan (flat/estereo/cubemap) ganham um primeiro tonemap PQ->SDR
(Reinhard simples, sem leitura de metadado HDR ainda) atras de um flag
isHdr no push constant — GLES (congelado ate 1.0) nao foi tocado.

Validado por compilacao real: cargo ndk check/clippy em core+bridge,
cargo test -p media-logic (215 testes), glslc nos 6 shaders alterados,
e build nativo Vulkan completo (gradle :app:buildCMakeDebug) linkando
com sucesso. Sincronismo A/V, estabilidade do driver com o novo padrao
de threading e o tonemap visual ainda precisam de validacao no headset.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NRZvyVVEKfagyCNkVSa6pM
Fecha o campo de observabilidade previsto para a separação decode/
apresentação (commit anterior, bb3ee38): quantos frames o MediaCodec já
decodificou mas a video_thread ainda não liberou/mostrou, vindo de
get_video_presentation_pending() no bridge Rust.

Caminho completo (backend Vulkan; GLES fica com o default 0, congelado):
AppState::videoPresentationPending (polling ~1Hz) -> DebugStats::
videoPresentationPending -> chave "presentation_pending" no TSV
(SerializeDebugStats) -> NativeDebugStats.presentationPending
(DebugStatsParser) -> coluna video_presentation_pending no CSV
(SCHEMA_VERSION 5 -> 6) -> linha "Frames Pending Display" na seção
Rede & Buffer do HUD "Stats for Nerds" (en/pt-BR/es).

Testes de DebugTelemetryExporterTest atualizados para a nova coluna
(índices de coluna deslocados +1 a partir de video_q_depth). 260 testes
Kotlin (testDebugUnitTest) e o build nativo Vulkan completo (gradle
:app:buildCMakeDebug) verificados passando/linkando.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NRZvyVVEKfagyCNkVSa6pM
… e docs/phases

- Adiciona version.properties como fonte unica da verdade alinhada com docs/phases (v0.4.7)
- Integra app/build.gradle.kts para carregar version.properties com suporte a override (-PappVersionName, -PappVersionCode)
- Atualiza scripts/build.sh para propagar variaveis de versao ao Gradle
- Atualiza .github/workflows/release.yml para gerar tags e releases no formato v0.4.7-build.X e anexar tucaVR-v*.apk
@BGLuis
BGLuis merged commit e0f29dc into main Sep 16, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant