Skip to content

Device testing: v2 and open PRs (report + checklist) #53

Closed

Description

@compot-dev

Tracking issue for on-device testing of v2 and the open PRs. Results are added here as comments; the checklist below is the plan.

Rule: only CI builds from GitHub Actions are tested (workflow artifacts for working branches, the latest release for v2/basic). No local builds.

Test bench

Device AG-216 Android TV box, Android 10 (API 29), armeabi-v7a, 1280×720
HW decoder OMX.allwinner.video.decoder.avc (the board reports itself as Amlogic, but the codec is Allwinner)
Camera 1 XM / H264DVR 1.0, H.264 1280×720 (coded 1280×736), 25 fps, no audio
Camera 2 OpenIPC camera, codec/audio/resolution can be changed during the test — being set up

How to continue (from any session)

Everything needed to pick this up is in this issue. Update it as you go: tick the checklist in this body, post each test run as a comment (build, commit, result table, findings).

1. Device access

  • Device: 172.17.32.144:5555, lab network, ADB over TCP, no authorization prompt, shell uid 2000.
  • adb is not installed system-wide on the lab host. Download Google's platform-tools to a temp dir:
    curl -sSLO https://dl.google.com/android/repository/platform-tools-latest-linux.zip
    unzip -q platform-tools-latest-linux.zip
    export ADB="$PWD/platform-tools/adb -s 172.17.32.144:5555"
    $PWD/platform-tools/adb connect 172.17.32.144:5555
    $ADB shell getprop ro.product.model   # AG-216
  • Camera 1 is on the same network as the device. Its RTSP URL (with credentials) is not published here. It is already saved in the app on the device: build fix: decoder recovery and lifecycle — Quad H.265, resume, thread leak, pause (#20 #21 #22 #23 #32) #48 is installed and stores it. Ask in this thread if you need it.

2. Builds (CI only)

  • v2 / basic: gh release download latest -R OpenIPC/decoder -p decoder-v2.apk -p decoder.apk
  • PR branches: build.yml builds signed APKs only on push runs (not pull_request), artifact name decoder-<branch with / → ->:
    RUN=$(gh run list -R OpenIPC/decoder -b fix/decoder-lifecycle -e push -L 1 --json databaseId -q '.[0].databaseId')
    gh run download $RUN -R OpenIPC/decoder -n decoder-fix-decoder-lifecycle
  • Every build is com.openipc.decoder with the release signature. Switching from a debug build needs adb uninstall first, which wipes the settings.
  • Set a camera without the UI (works in every build): am start -a android.intent.action.SEND -t text/plain --es android.intent.extra.TEXT '<rtsp url>' -n com.openipc.decoder/.Decoder. Only fix: decoder recovery and lifecycle — Quad H.265, resume, thread leak, pause (#20 #21 #22 #23 #32) #48+ saves it; older builds forget it after a pause.

3. Smoke test script

smoke.sh <apk> <label> (needs ADB and CAM_URL in the environment)
#!/bin/bash
# usage: ADB="adb -s 172.17.32.144:5555" CAM_URL='rtsp://...' ./smoke.sh <apk> <label>
PKG=com.openipc.decoder; APK=$1; L=$2; OUT=res/$L; mkdir -p $OUT
mask(){ sed -E 's#password=[^_ ]+#password=***#g; s#(rtsp://[^:/@]+:)[^@]*@#\1***@#g'; }
$ADB uninstall $PKG >/dev/null 2>&1
echo "[$L] install: $($ADB install -r -t "$APK" 2>&1 | tail -1)"
echo "[$L] version: $($ADB shell dumpsys package $PKG | grep -m1 versionName | tr -d ' ')"
$ADB logcat -c
$ADB shell "am start -W -a android.intent.action.SEND -t text/plain --es android.intent.extra.TEXT '$CAM_URL' -n $PKG/.Decoder" | grep -E "Status|TotalTime" | tr '\n' ' '; echo
sleep 15
PID=$($ADB shell pidof $PKG); echo "[$L] pid=$PID threads=$($ADB shell ls /proc/$PID/task | wc -l) top=$($ADB shell dumpsys activity activities | grep -m1 mResumedActivity | awk '{print $4}')"
$ADB exec-out screencap -p > $OUT/1_start.png
for i in 1 2 3; do   # Home -> back, 3 times
  $ADB shell input keyevent KEYCODE_HOME; sleep 3
  $ADB shell am start -a android.intent.action.MAIN -c android.intent.category.LEANBACK_LAUNCHER -n $PKG/.Decoder >/dev/null; sleep 8
done
PID2=$($ADB shell pidof $PKG); echo "[$L] after 3x resume: pid=$PID2 threads=$($ADB shell ls /proc/$PID2/task | wc -l) top=$($ADB shell dumpsys activity activities | grep -m1 mResumedActivity | awk '{print $4}')"
$ADB exec-out screencap -p > $OUT/2_resume.png
$ADB logcat -d | mask > $OUT/logcat.txt
echo "[$L] decoder starts=$(grep -c 'Start video decoder' $OUT/logcat.txt) fatal=$(grep -c 'FATAL EXCEPTION' $OUT/logcat.txt) anr=$(grep -c 'ANR in' $OUT/logcat.txt)"
grep -E 'FATAL EXCEPTION|ANR in' -A8 $OUT/logcat.txt | head -20

Pitfalls:

4. Next steps

  1. Camera 2 (OpenIPC) is being set up by the maintainer. Once its IP, SSH (root) and RTSP URL are posted here and the device can reach it: Quad mode: H.265 cameras stay black #20 (Quad H.265), Video never recovers after a MediaCodec error #21 (switch codec live, e.g. cli -s .video0.codec h265 + restart majestic), Image is cropped at the edges on non-16:9 screens #17 (4:3 stream), audio.
  2. Without camera 2: fix: screenshot permission (#28), back handling (#30), cleanup (#35) #50 checks (Screenshots fail on Android 6–9: storage permission is never requested #28 screenshot, Android 16 (targetSdk 36): migrate Back handling to OnBackInvokedCallback #30 back), fix: decoder recovery and lifecycle — Quad H.265, resume, thread leak, pause (#20 #21 #22 #23 #32) #48 screen off/on and the 20-switch thread test (Thread leak on every camera switch or URL save #23).
  3. When every item for a PR is ticked, comment on that PR with a link to the result here and remove awaiting device test.

Smoke test (2026-10-12)

Procedure: install → set the camera via a share intent (ACTION_SEND + EXTRA_TEXT) → 15 s → screenshot → 3× (Home → back via launcher) → screenshot → logcat; thread count from /proc/<pid>/task.

Build Start After 3× Home → back Threads Crash / ANR
basic 1.07.1 (latest) ✅ picture ❌ falls back to the default 192.168.1.10 26 → 27 none
v2 1.28 (latest) ✅ picture ❌ "No camera configured" 24 → 20 none
#48 fix/decoder-lifecycle 31b78e3 ✅ picture ✅ picture after each resume, RTSP + decoder restart 26 → 26 none
#49 fix/video-fit f9485ea ✅ picture ❌ same as v2 (no #48 fix) 24 → 20 none
#50 fix/platform-cleanup c32495f ✅ picture ❌ same as v2 (no #48 fix) 24 → 20 none

Findings:

Checklist

#48 decoder lifecycle

#49 video fit

#50 platform cleanup

Audio (needs camera 2)

  • AAC
  • G.711 μ-law / A-law
  • L16 PCM

Activity

  1. added
    in progressBeing worked on right now (open PR)
    hardwareNeeds real hardware: device or camera
    on Oct 12, 2026
  2. compot-dev commented on Oct 12, 2026

    @compot-dev
    CollaboratorAuthor

    Update from the session that writes the PRs (no device access used from here; the device is left to this thread).

    #48 changed after the tested commit 31b78e3. Please re-run the smoke test on the current head:

    • setEnabled(false) no longer takes the decoder lock on the UI thread; the codec is released on a decoder-release thread.
    • Quad cells are now wrapped in a FrameLayout. Without this, the first Home → back in Quad mode would crash with ClassCastException in clearQuadViews(). The code never ran before Active camera and quad mode are not restored on resume #22 was fixed. Please add to the checklist: Quad mode, Home → back: no crash, the black placeholders disappear when each camera starts.

    New PRs awaiting device test, each with its own checklist in the PR description:

    Stacked branches build on push like the others, e.g. artifact decoder-feat-quad-audio.

  3. compot-dev commented on Oct 12, 2026

    @compot-dev
    CollaboratorAuthor

    Run 2 — #48 head 0a2e550 (2026-10-12, this session)

    Build: CI artifact decoder-fix-decoder-lifecycle @ 0a2e550. Camera 1 (XM H.264 1280×736, no audio).

    Check Result
    Smoke: start → 3× Home → back ✅ picture after each resume; threads 26 → 26; 4 decoder starts; 0 crash / ANR / codec errors
    #23 20 camera switches (slot 1 ↔ 2 via the menu) ✅ threads 22 → 22
    #22 Quad → Home → back ✅ no crash (the ClassCastException fix works); Quad comes back with video
    #22 screen off/on (KEYCODE_SLEEP / WAKEUP) ✅ video back (the box then shows its own "Update Alert!!" firmware dialog, unrelated to the app)
    Quad from the menu ✅ cell starts in < 1 s (3 attempts); ⚠️ seen once: the cell stayed black until the next resume (no session started). Not reproduced; a log line was added to catch it

    New findings

    1. A shared link sent to an app that is already open is ignored. am start … SEND answered "intent has been delivered to currently running top-most instance": onNewIntent() was not overridden, so the link never reached loadSettings(). In the switch test slot 2 therefore stayed empty, which is why there were only 11 decoder starts for 20 switches. Fixed in fix: decoder recovery and lifecycle — Quad H.265, resume, thread leak, pause (#20 #21 #22 #23 #32) #48 (onNewIntent() → setIntent()).
    2. The camera password is written to logcat. The Content-Base header echoes the XM URL with password= in its path. Filed as Camera password is written to logcat #55 and fixed in fix: decoder recovery and lifecycle — Quad H.265, resume, thread leak, pause (#20 #21 #22 #23 #32) #48 (all logged RTSP lines and URL errors are redacted).
    3. Log noise: every intentional stop() logged "RTSP connection failed: Socket closed". Removed in fix: decoder recovery and lifecycle — Quad H.265, resume, thread leak, pause (#20 #21 #22 #23 #32) #48.

    Next: re-test the new #48 head with the shared link, then #32 (4 unreachable cameras in Quad → Home, measure the pause), #49, #50, #51 and #54.

  4. compot-dev commented on Oct 12, 2026

    @compot-dev
    CollaboratorAuthor

    Run 3 — #48 at 211f9d6 → a3dbd6c → cfbb492, camera 2 added

    Camera 2: OpenIPC on SigmaStar SSC33x (sensor SC2336P), Majestic Lite, 1920×1088. Initial stream: H.264 + Opus audio (opus/48000/2) + an ONVIF metadata track. Codec changes via cli -s + /etc/init.d/S95majestic restart. Credentials are not published here.

    Check Build Result
    Smoke (start → 3× Home → back) 211f9d6, a3dbd6c, cfbb492 ✅ every time; threads stable (25–27); 0 crash / ANR
    #55: camera password in logcat 211f9d6 ✅ 0 occurrences (was in clear text before)
    #23: 20 switches 211f9d6 ✅ threads 23 → 23; no false "connection failed" lines
    #32: Quad with 3 unreachable cameras + 1 live → Home 211f9d6 ✅ 0 pause timeouts / ANR / skipped frames; Home → launcher ≈ 1.4 s incl. adb polling (v2 1.28: 2.2 s in Quad)
    #30: Back with the menu open / WebUI dialog open #50 cc60036 ✅ closes the menu or dialog; the next Back leaves the app
    #28: long-press screenshot on Android 10 #50 cc60036 ✅ Pictures/OpenIPC/Screenshot_*.png (1.5 MB), no prompt
    Shared link to the running app cfbb492 ✅ after the singleTop fix (see below)
    Camera 2 H.265 1920×1088 in single view cfbb492 ✅ picture
    #20: Quad with H.264 (cam 1) + H.265 (cam 2) cfbb492 ✅ both cells decode (video/avc + video/hevc)

    Findings and fixes (all pushed to #48)

    1. A link shared to the running app was ignored. am start (and any sender using FLAG_ACTIVITY_NEW_TASK) only brought the task to the front; with the standard launch mode nothing reached the app. Fixed with launchMode="singleTop", and onNewIntent() now restarts the streams, because Android 10 delivers it without onPause()/onResume().
    2. The audio thread spins at 100 % CPU in Quad. startQuad() shut the executor down without bumping the generation, so the audio loop kept calling playPcmFrame(), which returned at once with the interrupt flag set. Seen as rtsp-audio at 91–100 % in top -H. The same pattern exists in v2. Fixed in e8a7f2d.
    3. H.265 started its decoder twice (0.6 s apart): the first H.265 packet was taken as a codec switch. Fixed in e8a7f2d.
    4. ⚠️ Intermittent: Quad entered from the menu shows a black screen and the UI stops drawing. gfxinfo frame count frozen, the Quad container laid out at 0×0, no ANR, main thread sleeping; Home → back recovers it. Seen 2 times out of 6, both times right after an install started via a share intent. It was not reproduced on demand, so the cause is still unknown. Re-checking with the CPU-spin fix (2), which was active both times.
  5. compot-dev commented on Oct 12, 2026

    @compot-dev
    CollaboratorAuthor

    Run 4 — final device results before merging (2026-10-12)

    Cameras: 1 XM H.264 (no audio) · 2 .126 OpenIPC, H.265 + Opus · 3 .133 OpenIPC (SSC33x, Majestic Lite), codec and audio switched live with cli -s + Majestic restart. On this Majestic Lite build .audio.codec supports opus, aac (mpeg4-generic/8000/1) and PCM (L16/8000/1); G.711 values fall back to L16, so G.711 could not be tested.

    PR Check Result
    #48 4660bba smoke (3× Home → back) ✅ 4 decoder starts, threads 26 → 26
    #48 #21 live H.265 → H.264 → H.265 on cam 3, single view ✅ reconnects and re-creates the decoder for the new codec; one H.265 codec error recovered after 500 ms
    #48 #20 Quad H.264 + H.265 ✅ (run 3)
    #48 spinning audio thread ✅ gone (top -H: no thread above 50 %)
    #49 f9485ea #17 16:9 stream on an emulated 4:3 screen (wm size 960x720) ✅ letterboxed, y 84..635. v2 crops the left and right edges
    #49 4:3 stream (1440×1080) on the 16:9 TV ✅ pillarboxed, same as v2
    #52 44d1be2 (+#51, +#48) Opus 48 kHz stereo ✅ AudioTrack active, ≈ 48 000 frames/s, no underruns after start
    #52 AAC mpeg4-generic/8000/1, live switch ✅ ≈ 8 000 frames/s
    #52 L16 8 kHz, live switch ✅ ≈ 8 000 frames/s
    #51 (in #52 build) #12 Quad audio: long press cell 1 → cell 2 → again ✅ no audio → cell 1 plays (badge) → cell 2 plays, no reconnect → muted
    #54 6b9a2a4 upgrade over the #52 build, keeping data ✅ all camera URLs kept and working (they are re-saved encrypted on first load)
    #54 a second upgrade over itself ✅ URLs still decrypt; the Keystore key survives updates

    Playback is measured from dumpsys media.audio_flinger (server position of the app's track), since sound cannot be heard remotely.

    Deferred: #56 (Quad sometimes not laid out after the task is brought to the front by am start). The mitigation is in #48; it did not recur in runs 3–4.

    Next: merge in order #48 → #51 → #52 → #54 → #49 → #50, each after CI and Qodo agree.

  6. compot-dev commented on Oct 12, 2026

    @compot-dev
    CollaboratorAuthor

    Merge progress (2026-10-12)

    PR Status
    #48 lifecycle/decoder recovery ✅ merged; #20 #21 #22 #23 #32 #55 closed
    #51 Quad audio ✅ merged; #12 closed
    #54 credential store ✅ merged; #16 stays open (Android 5 fallback, transport)
    #52 audio formats Qodo: 3 new LATM findings fixed (lost first fragment, buffer cap, 960/core-coder configs refused) + tests; waiting for CI
    #49 video fit rebased onto v2, tests and build OK locally; waiting for CI
    #50 platform cleanup rebased onto v2, tests and build OK locally; waiting for CI

    Deferred: #7, #13, #15, #56.

  7. compot-dev commented on Oct 12, 2026

    @compot-dev
    CollaboratorAuthor

    Final: all PRs merged (2026-10-12)

    #48, #51, #54, #52, #49 and #50 are merged into v2. Closed: #12, #17, #20, #21, #22, #23, #28, #30, #31, #32, #35, #55.

    Smoke test of the final v2 CI build (55f07ff, decoder-v2.apk from the latest release, installed as an upgrade over the previous build):

    Check Result
    install as an upgrade, settings kept ✅
    start from a shared link ✅ Status ok, 825 ms
    3× Home → resume ✅ same pid, 28 threads (no leak), activity on top
    decoder starts / FATAL / ANR / codec errors / NAL drops 4 / 0 / 0 / 0 / 0
    picture after resume ✅ fitted, no cropping

    Remaining open: #14 (G.726, LATM cpresent=1), #16 (Android 5 storage, transport encryption); deferred: #7, #13, #15, #56.

  8. compot-dev commented on Oct 12, 2026

    @compot-dev
    CollaboratorAuthor

    Closing: all PRs from this test round are merged (#48–#52, #54, #57) and the final v2 build 55f07ff passed the smoke test on the device. This issue stays as the reference for future device test rounds: the checklist, the per-issue result tables, the 4:3 emulation via wm size, audio checks via the audio_flinger frame position, and the codec switching on Majestic (.video0.codec, .audio.codec). New rounds should open a new issue with the same structure and link back here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    hardwareNeeds real hardware: device or camera

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions