Updated 2026-09-14. This file is loaded into every session automatically, which makes a stale banner here more expensive than anywhere else in the repository — it is the first thing any new reader, human or agent, believes. The 07-25 text below says the last code change was 2026-07-03, that host tests are "39 UI + 8 DB", and that the whole critical path is blocked on one device session. All three are wrong. This is the same failure already caught for
ROADMAP.md(docs/AUDIT_2026-09-01.md§D2) and fixed there the same way.Where the project actually is, 2026-09-14 (
7860396, v0.3.4):
Releases shipped v0.3.0 → v0.3.4, with a one-click Windows/Linux installer Offline gates 549 Rust tests, 41 harness scenarios, 23 C/C++ files syntax-clean, 234 golden pixel hashes — all green, all re-run 2026-09-14 The headline feature USB-DAC → LDAC ran end to end (2026-09-12, owner-reported, no log captured) Landed since this banner FM tuner, Bluetooth, NFC, playlists, on-screen keyboard, liked-songs sync, device settings, palettes (device-verified), type scale, lyrics and search Still device-gated docs/DEVICE_CHECKLIST.md— 11.9, the Windows installer (the only Windows install path): the owner reports running the v0.3.3 installer, whoseinstaller/is identical to v0.3.4's; platform and log not yet recordedThe live documents, in order of what you probably want:
- What to do next, and the skins design system:
docs/PLAN_2026-09-14.md— current audit + ordered plan.- Feature state (works / partial / stationary):
cinder-home/STATUS.md— the single source of truth.- Device run sheet:
docs/DEVICE_CHECKLIST.md— safety rules first.- Structural weaknesses:
docs/SHORTCOMINGS.md— cited by section ID (note: §A1's coverage table is superseded byPLAN_2026-09-14.md§A1).- Every audit, and which are history:
docs/README.md.- RE detail:
analysis/RE_playerservice_sound.md, plusanalysis/{E,F,G,H}_*/RE_findings.md.Parts B–H below remain reference-grade and current — the environment setup, the RE findings and the
.UPGprocedure are all still accurate. It is only the state and plan text that has aged, and it is kept verbatim below as history.
This document began (v1.4) as a pre-device onboarding plan ("when the NW-A55 arrives"). That premise is now historical. The device has been in hand for weeks, backed up (wbrt), flashed, soft-bricked-and-recovered twice, and the Cinder replacement player runs on it as the easel Home app. Read the sections below as the still-accurate environment + RE reference (Parts B–H are reference-grade and current), but for where the project actually is and what to do next, the live docs win:
- Current feature state (what works / partial / stationary):
cinder-home/STATUS.md— the single source of truth.- Forward plan / next stages:
docs/DEVICE_CHECKLIST.md— the ordered run sheet for everything device-gated. (cinder-home/ROADMAP.mdis a 2026-07-28 snapshot; it now says so at the top.)- Open decisions right now:
docs/AUDIT_2026-09-01.mdPart D. Every document indocs/is indexed bydocs/README.md, which also says which ones are history.- RE detail behind each feature:
analysis/RE_playerservice_sound.md, plus per-subsystemanalysis/{E,F,G,H}_*/RE_findings.md.One-line status: all genuinely-offline work is done and daily-usable (host tests green: 39 UI + 8 DB; qemu preflight passes). The entire remaining critical path is device-gated and blocked on ONE thing — a first successful device session that runs the discovery dump. Last code change was 2026-07-03 (tenth round); the tree is clean and the resume point is that device session (ROADMAP §"The device session — critical path"). The pre-device "Phase 8 / Part E" milestone plan below is superseded by that roadmap; Part E survives as the procedure reference.
Purpose: A single onboarding document that takes you from a stock Windows PC to a working analysis environment, runs the existing host-side pipeline, and then adds the device-side procedure. (v1.5: the device-side procedure has now been executed — see the state banner above; the steps below remain the canonical how-to for reproducing it.)
Relationship to existing repo: The repo already has a 7-phase host-side pipeline
(Makefile, phases/phase1–phase7, CLAUDE.md, docs/). This document does not
replace those — it wraps them with (a) Windows/WSL environment setup the phases assume but
don't provide, and (b) a new device-side procedure ("Phase 8") that the host-side phases
explicitly defer.
v1.4 status note: The MT8590 SoC is confirmed (docs/baseline_v1.4.md §4.1, citing
unknown321/wbrt README and Wampy MAKING_OF.md). Phase 3 is a confirmation step, not
discovery — phases/phase3_soc_id.sh now checks for MT8590-specific markers in the
extracted firmware and reports them as evidence.
Cinder app status (live): the replacement player is built and daily-usable. The single
source of truth for which features are fully functional vs partial vs stationary is
cinder-home/STATUS.md ("Feature status" matrix) — read it before promising any feature.
RE detail behind each: analysis/RE_playerservice_sound.md. Build = cinder-home/build.sh [stable|dev] (two channels from one tree; dev adds adb for fast iteration).
The analysis pipeline is Linux bash + Linux tools (binwalk, dtc, qemu-arm-static,
loop-mounting ext4, cross-compilers). That all runs in WSL2. But several operations
must run on native Windows because they talk to the device over USB with
Windows-only drivers:
| Task | Where it runs | Why |
|---|---|---|
| Phases 1–7 (firmware analysis, cross-compile) | WSL2 (Ubuntu) | Linux toolchain; loop-mount; qemu |
Reading/editing/decrypting .UPG (upgtool) |
WSL2 | Rockbox tool builds on Linux |
Installing a .UPG to the device |
Either | cinder-installer sends the vendor SCSI command itself: SCSI pass-through on Windows (administrator), SG_IO on Linux (root). Sony's SoftwareUpdateTool.exe is no longer used or embedded |
| Installing Walkman One / Wampy / scrobbler | Native Windows | Their installers are .exe |
Full eMMC backup/restore (wbrt) |
Native Windows | Needs MediaTek USB VCOM driver (VID_0E8D) |
Low-level MediaTek access (mtkclient, SP Flash Tool) |
Native Windows (or WSL2 + usbipd) | MTK preloader/BROM USB driver |
adb/scsitool device shell |
Either (WSL2 needs usbipd-win for USB passthrough) | adb works in both; raw USB needs passthrough |
Rule of thumb: analyze in WSL, touch the device from Windows. The one exception is
adb shell access, which can be made to work from WSL2 with usbipd-win (Part F).
wsl --install -d Ubuntu-24.04
wsl --set-default-version 2
# reboot when prompted, then launch "Ubuntu" from Start menu to create your userVerify you're on WSL2 (not 1):
wsl -l -v # VERSION column must say 2The repo's make check-deps looks for: git binwalk dtc file readelf strings nm qemu-arm-static cargo rustup clang. Install them:
sudo apt update
sudo apt install -y \
git build-essential \
binwalk device-tree-compiler binutils file \
qemu-user-static \
clang lld llvm \
python3 python3-pip \
android-tools-adb \
libssl-dev pkg-config
# Rust + the ARM musl target the project cross-compiles to
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source "$HOME/.cargo/env"
rustup target add armv7-unknown-linux-musleabihfOptional but recommended for deeper RE:
# unblob is a stronger alternative to binwalk for some sectors
pip3 install --user unblob
# Ghidra (for HgrmMediaPlayerApp / libSoundServiceFw decompilation) — install via:
sudo apt install -y default-jdk
# then download Ghidra from github.com/NationalSecurityAgency/ghidra/releases and unzipA musl cross-compiler for the C shim (Phase 6 looks for arm-linux-musleabihf-gcc):
# Easiest: grab a prebuilt toolchain from musl.cc
cd ~ && wget https://musl.cc/arm-linux-musleabihf-cross.tgz
tar xf arm-linux-musleabihf-cross.tgz
echo 'export PATH="$HOME/arm-linux-musleabihf-cross/bin:$PATH"' >> ~/.bashrc
source ~/.bashrcThen confirm:
cd /path/to/repo
make check-deps # should now report all greenClone the repo inside the WSL filesystem (~/projects/...), not under /mnt/c/....
Loop-mounting ext4 and fast find/grep over the rootfs are dramatically slower on the
Windows-mounted drive. You can still open the files from Windows via \\wsl$\Ubuntu\home\....
Install these on the Windows side so they're ready when the device arrives:
- MediaTek USB VCOM driver — required for
wbrtand any MTK tool. The device enumerates asVID_0E8D. (wbrt's README has the driver-cleanup steps if Windows grabs the wrong one.) wbrt(Walkman Backup/Restore Tool) —github.com/unknown321/wbrt/releases. This is your brick insurance. Full eMMC backup before any write.- Walkman One installer —
mrwalkman.com(NW-A50 series page). The recommended baseline FW. - Wampy installer
.exe—github.com/unknown321/wampy/releases/latest. - scrobbler installer —
github.com/unknown321/scrobbler/releases(for log-format reference). - (Optional)
mtkclient—github.com/bkerler/mtkclient, only if you later need BROM/preloader-level eMMC access. Python-based; needsusbdkdriver on Windows.
Phase 1 (make phase1) already clones the first five into artifacts/repos/. This table is
the reading guide — which file in each repo answers which project question.
| Repo | Cloned by | Read this first | Answers |
|---|---|---|---|
unknown321/wampy |
phase1 | MAKING_OF.md, then the other MAKING_OF_*.md, ALSA.md, kernel.md, installer/run.sh, src/Controller.cpp |
The entire userspace map: init hooks, LD_PRELOAD points, view-model surface, filter chain, ALSA topology, boot-image gotcha, .UPG installer pattern |
unknown321/scrobbler |
phase1 | README.md, INSTALL.md, playerevents/audioscrobbler/daemon source |
.scrobbler.log format and path (root of internal storage), the track-state IPC, the "beeps off" gotcha, adb-vs-scsitool install |
unknown321/wbrt |
phase1 | README.md |
MT8590 confirmation, MediaTek VID/PID, backup/restore procedure |
Rockbox/rockbox (sparse: utils/nwztools) |
phase1 | upgtools/ (build upgtool), database/nvp/ (KAS + NVP slot map), scsitool/ |
.UPG pack/unpack, per-model KAS (64 bytes), NVP slot definitions, SCSI backchannel |
roobscoob/SonyWalkmanFirmwarePatcher |
phase1 | upgDocs.md |
The clearest one-page V2 .UPG format + crypto spec |
zhangboyang/llusbdac |
add manually | README, the module source |
Low-latency USB-DAC kernel module precedent — central to the USB-DAC+LDAC question |
Add the one missing repo to your Phase 1 clone list (or clone by hand):
git clone --depth=1 https://github.com/zhangboyang/llusbdac \
artifacts/repos/llusbdacReading order for a new engineer: wbrt README (5 min, confirms platform) → roobscoob
upgDocs.md (15 min, the file format) → all Wampy MAKING_OF_*.md (one afternoon, the
whole device) → Rockbox nwztools source (as needed for KAS/NVP/SCSI).
This is the existing pipeline. Run it in order. Each phase gates on the previous via a sentinel file.
- Stock A55
.UPG: Sony support downloads → "NW-A55 firmware" →NW_WM_FW.UPG(v1.02 or latest). Place atartifacts/stock/NW_WM_FW.UPG. - Walkman One
.UPG:mrwalkman.comNW-A50 page. Place atartifacts/walkmanone/WalkmanOne.UPG.
make check-deps # all green from Part B
make phase1 # clone repos, build upgtool, unpack both .UPG files
make phase2 # binwalk every sector; extract boot image; loop-mount rootfs
# (phase2 may print a sudo helper: sudo bash artifacts/mount_rootfs.sh)
make phase3 # SoC: now a CONFIRMATION step — expect to see mt8590 markers
make phase4 # rootfs deep-dive 4a–4h (init flow, toolchain, view-models,
# SoundServiceFw symbols, USB-DAC routing, hold switch, 2038)
make phase5 # diff stock vs Walkman One — the "what W1 changes" recipe
make phase6 # cross-compile hello-walkman (armv7 musl) + C shim; qemu-test
make phase7 # .UPG repack round-trip — proves modify→repack→unpack is sound| Your question | Phase that informs it | Output file |
|---|---|---|
| Full UI replacement, auto-boot | phase4b (init flow → HgrmMediaPlayerApp service) | analysis/4b_init_flow.txt |
| Keep all audio features | phase4c (Sony clang version), phase4e (SoundServiceFw symbols) | analysis/4c_*, analysis/4e_* |
| Queue / shuffle-by-album | (none host-side — pure app logic; see baseline §5.12) | n/a |
| USB-DAC + LDAC out | phase4f (routing verdict from strings) — narrows but cannot close; needs device | analysis/4f_usb_dac_routing.txt |
The USB-DAC question is the one host-side analysis can only narrow. Phase 4f greps
HgrmMediaPlayerApp, libSoundServiceFw.so, and llusbdac.ko for routing/exclusivity
strings to guess which of the three candidates enforces the block — but the definitive
answer comes from Phase 8 (device-side).
The host-side phases are explicitly "no device required." This is the missing piece. Do these in order; the ordering is a safety gradient (back up first, read before write, reversible before irreversible).
- Connect the A55, let Windows install the MediaTek VCOM driver (
VID_0E8D). - Run
wbrt, choose Backup. This dumps the full eMMC including NVP, serial, and factory settings. Store this backup somewhere safe and redundant. It is the only thing that can recover a brick on this device (there is no public USB DFU/EDL recovery for the audio SoC). - Note: a
wbrtbackup is device-specific — never restore one device's backup to another; it overwrites the serial and factory calibration with no recovery.
- Install Walkman One via its installer. This is the project's known-good baseline (everything downstream is measured against it, and Wampy/scrobbler are best-tested on it).
- Install Wampy on top. This gives you a known-working modded environment to probe from,
and a working
.UPGinstall path you can imitate.
Two routes; try adb first.
Route 1 — adb (preferred). Per the scrobbler INSTALL.md, adb is present on some configurations. From WSL2 you need USB passthrough (Part F), or just run adb from native Windows:
adb devices # confirm the A55 shows up
adb shell # interactive shell on the deviceRoute 2 — scsitool (no adb). Build Rockbox scsitool-nwz (in WSL) and use the USB-MSC
SCSI backchannel to read NVP and device info. Use this for NVP work even if adb is available.
On the device shell:
cat /proc/cpuinfo # CPU cores, features
cat /sys/firmware/devicetree/base/compatible # SoC compatible string (expect mt8590)
getprop ro.board.platform # expect: mt8590 (if property service present)
getprop ro.boot.console # expect: ttyMT1 (MediaTek UART prefix)
dmesg | head -100 # kernel boot log — machine name, SoC initThis confirms the v1.4 finding (MT8590) on your actual unit and records the exact sub-variant.
This is the single most important device-side investigation. Run the same commands in each audio mode and diff the output:
# Run this block in EACH of these modes:
# (a) normal file playback to 3.5mm
# (b) USB-DAC mode active
# (c) Bluetooth output (LDAC) active
# (d) Bluetooth receiver mode active
cat /proc/asound/cards # which cards exist
aplay -l # playback PCM devices (expect sonysoccard, 6 devices)
aplay -L # PCM device names incl. plugins
arecord -l # CAPTURE devices — KEY: is anything capturable?
amixer scontrols # mixer controls / routing switches
cat /proc/asound/card0/pcm*/sub*/status # which substreams are RUNNING
ls -l /dev/snd/ # device nodes presentWhat the result tells you:
- If a capture or loopback device appears during USB-DAC mode, you can route USB-PCM-in to the LDAC encoder → the feature is achievable in software.
- If no capture device ever appears and
llusbdac.kooutputs only tocxd3778gf-*, the routing is fixed at the kernel-module level → you'd need a customllusbdac.kobuild. - If the BT sink simply isn't present while USB-DAC is active, check whether it's BlueZ state (E5) or app policy (E6).
# While toggling USB-DAC mode on the device, watch what the player touches:
strace -f -p $(pgrep HgrmMediaPlayerApp) 2>&1 | grep -iE 'bluez|dbus|snd|pcm|usb|dac'
# In a second shell, watch BlueZ state:
dbus-monitor --system 2>/dev/null | grep -i bluez # (BlueZ 4 is old; may need hcitool/hciconfig)
hciconfig -a # BT adapter up/down across mode switch
cat /sys/class/android_usb/android0/functions 2>/dev/null # USB gadget config (MSC/MTP/DAC)Maps directly onto the three candidates in baseline §5.10:
- player calls
disconnect/bluezon USB-DAC entry → Candidate 1 (app policy) → easiest fix - a
libSoundServiceFwsource/sink enum flips → Candidate 2 → call routing APIs carefully llusbdac.kobinds a fixed ALSA sink → Candidate 3 → custom kernel module
# Via scsitool from the host (read-only — do NOT write yet):
./scsitool-nwz <dev> dump_nvp # read every reachable NVP node
# Confirm: destination code, SPS flag, KAS node (kas, 64 bytes), upgrade flagBack up the raw NVP partition before any write. Only after a verified backup should you
attempt any scsitool write (destination/region is reversible; the U-Boot password slot is
not — never write it).
- Build
hello-walkman(Phase 6 output) into a.UPGusingupgtool+ a Rockboxnwztools/scripts/exec_file.shtemplate. - Install it the same way Wampy installs (its
installer/run.shis the template). - Verify it runs at boot and logs. Include a bad-boot counter (Wampy's pattern) so a crash auto-reverts after N failed boots.
- Only after that works: build the
init.rcchange that swapsHgrmMediaPlayerApp's service entry for your binary (full UI replacement). Test with the bad-boot counter as the safety net.
If you want adb/mtkclient to reach the device from inside WSL rather than native Windows,
use usbipd-win:
# Native Windows, admin PowerShell:
winget install usbipd
usbipd list # find the A55's BUSID
usbipd bind --busid <BUSID>
usbipd attach --wsl --busid <BUSID># Inside WSL:
lsusb # should now show VID 0e8d (MediaTek) or the adb interface
adb devicesFor raw MediaTek BROM/preloader work, native Windows + usbdk is usually less fiddly than WSL
passthrough. Keep wbrt and SP Flash Tool on the Windows side.
Progress against this plan (2026-07-25): steps 1–10 are effectively DONE. Environment, reading, the host pipeline (phases 1–7), the stale-doc flip (MT8590 confirmed), the wbrt backup (E0), a stock+Wampy baseline, a device shell (via scsitool/MSC + dev-channel adb), the USB-DAC investigation (E4/E5 → the block is app-policy only, LDAC transmit is non-ALSA via
BtTransmitterService), and first-code-on-device (E7 → the full Cinder Home app, not just a hello-world) have all happened. What's left is not on this milestone ladder anymore — it's the device-gated wiring incinder-home/ROADMAP.md. Keep the list below as the historical route; use the roadmap for the live plan.
- Environment (Part B) — WSL2 + deps green on
make check-deps. Half a day. [DONE] - Read (Part C) — wbrt README → roobscoob upgDocs → Wampy MAKING_OFs. One day.
- Host pipeline (Part D) —
make phase1…phase7. One to two days. Produces the confirmed SoC, init map, toolchain version, SoundServiceFw symbols, the W1 diff recipe, a proven.UPGround-trip, and a cross-compiled hello-world. - Update stale docs — flip
CLAUDE.mdandphase3to "MT8590 confirmed." - Device arrives → backup (E0) —
wbrtfull dump. Non-negotiable, first. - Baseline FW (E1) — Walkman One + Wampy.
- Shell + SoC confirm (E2–E3).
- The USB-DAC investigation (E4–E5) — this is the make-or-break for the headline feature. Decide here whether USB-DAC→LDAC is "free," "needs kernel module," or "blocked."
- NVP characterization (E6) — read-only, then careful backups before any write.
- First code on device (E7) — hello-world service → bad-boot counter → full player swap. Now you're building the actual replacement player.
Features recap against this plan:
- Full UI replacement + auto-boot: unlocked at step 10. High confidence.
- Keep all audio features: depends on step 3 (clang version) + step 10 (shim). High confidence.
- Queue + shuffle-by-album: pure app logic in the replacement player; no blocker. High confidence. (Both genuinely absent from stock — baseline §5.12.)
- USB-DAC in + LDAC out: resolved at step 8. Uncertain until then — do not promise it as a feature before E4/E5. Host-side analysis (Part H) has narrowed this to Candidate 1 (app-policy enforcement) with high confidence.
This section captures the concrete findings from the first end-to-end pipeline run on the
stock firmware (NW-A50_V1_02.exe → NW_WM_FW.UPG, 112 MB). It supersedes the speculation
in docs/baseline_v1.4.md §5.10 with on-firmware evidence.
All seven host-side phases ran on stock firmware. Walkman One unpacked successfully as a cross-reference but is not the project's baseline (user runs stock).
| Phase | Status | Key output |
|---|---|---|
| 1 | ✓ | upgtool built; stock + W1 unpacked with model nw-a50 (KAS confirmed) |
| 2 | ✓ | Boot image (sector 2) = Android bootimg container (kernel + ramdisk); rootfs (sector 6) = 800 MB ext4 |
| 3 | ✓ | MT8590 confirmed on firmware: ro.board.platform=mt8590 in /build.prop, plus mt8590 strings in 9 libMtkOmx*/libmtk_drvb libraries. OQ1 closed on-firmware (not just by wbrt citation). |
| 4 | ✓ | Full rootfs deep-dive — see H3 below. The single most important output. |
| 5 | partial | Stock vs W1 sectors are renumbered (stock rootfs = sector 6, W1 = sector 7); a useful diff requires file-level comparison of extracted rootfs trees, not sector files. |
| 6 | ✓ | Rust hello-walkman cross-built for armv7-unknown-linux-musleabihf, 506 KB static, runs under qemu-arm-static. C shim toolchain (arm-linux-musleabihf-gcc) verified. |
| 7 | ✓ | UPG round-trip: 8/9 sectors byte-identical, sector 6 differs only because phase1 saved it -z-decompressed (ext4) vs the round-trip's compressed fwpup form — the mechanism is sound. |
- Sony's
NW-A50_V1_02.exeis a proprietary "Packman" self-extractor — 7z/binwalk/unblob cannot extract the innerNW_WM_FW.UPG. The reliable path is to run the.exeon Windows and copy the.UPGout of%TEMP%before clicking past the first dialog. - The
1_StockRevert_Walkman_One_A50.exein the Walkman One bundle contains a.UPGnamedNW_WM_FW.UPG, but it is not the Sony stock firmware — it's a custom revert payload built by MrWalkman that fails KAS validation againstnw-a50(the StockRevert procedure runs the genuine2_NW-A50_V1.02.exeafterwards to actually flash stock). upgtoolbuild requireslibcrypto++-dev(mg.cppbrute-force search, unused for known KAS but a hard build dep).upgtoolflags — the original phase scripts referenced-xand-d; the actual flags are-e(extract) /-c(create), with-m <model>mandatory and-o <prefix>for output.-z <idx>decompresses sector<idx>fromfwpupframing.- Mounting the rootfs doesn't require sudo:
7z x 6.bin -o<dir>reads ext4 natively. Phase 2 was updated to do this automatically and detect sectors byfileoutput rather than filename pattern.
The baseline_v1.4.md §5.10 open question — where is USB-DAC-and-BT mutual exclusion
enforced? — narrows to Candidate 1: app-policy enforcement in HgrmMediaPlayerApp.
The evidence:
1. The kernel-level candidate is dead for stock.
llusbdac.ko does not exist in the stock rootfs at all. It is a Wampy/Walkman One add-on.
Stock USB-DAC mode is handled by libUsbDeviceAudioPlayerService.so (Sony-built) which
writes PCM to ALSA via libaudiohal-uacalsasingletrack.so. So Candidate 3 (kernel-fixed
sink) is ruled out for stock.
2. The USB mode manager is not the gate.
libUsbMgrServiceFw.so (the service deciding MSC/MTP/ADB/UAC) contains zero references
to Bluetooth, BT, disconnect, or disable. It only manages USB power supply mode from a UAC
host. So Candidate 2b (USB-mode manager forcing BT teardown) is ruled out.
3. The audio framework supports concurrent tracks of different types.
libSoundServiceFw.so logs "Cannot create multiple tracks that have same type" — i.e.
the constraint is on duplicate types, not on coexistence of different types. The
SoundServiceImpl::CreateTrack(TrackType) and OpenModulesIn(TrackType) API explicitly
parameterizes by type. Two evidence-grade indicators that this is real multi-track
infrastructure, not a vestige:
libaudiohal-dualtrackmixalsa.soexists — a HAL plugin that mixes two tracks into a single ALSA sink.- The full HAL plugin catalogue (
vendor/sony/lib/libaudiohal-*.so):a2dpsnksingletrack(BT-receive sink, Walkman as BT speaker),adleralsa(CXD3778GF wrapper — references/sys/module/snd_soc_cxd3778gf/parameters),analyzer,dualtrackmixalsa,genericalsa,listener,uacalsasingletrack(USB-DAC mode → ALSA).
4. The BT transmit path is a complete, callable service.
libBtTransmitterService.so exposes:
SetCurrentSource(bool)— declare which logical source is activeSetLdac(bool)— enable/disable LDAC codecSetLdacSoundQuality(BtLdacSoundQuality)— Auto / 990 / 660 / 330 kbpsNotifyOpenAudio()/NotifyCloseAudio()— open/close the streaming pipeNotifyPcmPreferredSize(uint16_t)— chunk size negotiationGetCapabilities(vector<BtA2dpConfiguration>)— query peer capabilities
The exported class factories BtTransmitterServiceFactory::CreateInstance and
BtTransmitterServiceClientFactory::CreateInstance mean a replacement player can
instantiate this service from outside.
5. The block is in the app UI flow.
HgrmMediaPlayerApp contains the embedded QML strings:
disconnectMsgOverlay, 1DisconnectView, 1DisconnectComponent, 1DisconnectModel,
1DisconnectWindowViewModel, GoToBluetoothSetting, usbDacDeviceWindow.
These describe an overlay dialog shown when the user enters USB-DAC mode that prompts them
to disconnect Bluetooth, with a button that navigates to the Bluetooth settings page. The
exclusivity is therefore implemented as a UI screen plus an explicit BT-disconnect call,
not as a runtime constraint of the underlying services.
Sony bundles many services into a generic hagodaemon (Hagoromo daemon) host process. From
init.hagoromo.rc (extracted from the boot-image ramdisk, sector 2), the services
relevant to the USB-DAC→LDAC project are:
hagoromoN |
Services hosted | Relevance |
|---|---|---|
hagoromo8 |
UsbHostConnectionService, UsbDeviceConnectionService, UsbDeviceAudioPlayerService |
USB-DAC input side — receives PCM from USB-gadget UAC |
hagoromo11 |
SoundServiceFw |
Central audio routing — SetSourceTypeTrack, CreateTrack(TrackType) |
hagoromo22 |
UsbMgrServiceFw |
USB mode selector — confirmed not a BT gate |
hagoromo24 |
WiredHpServiceFw |
3.5 mm headphone sink (current USB-DAC output target) |
hagoromo27 |
BtCommonService, BtTransmitterService, BtBleCommonService, BtBleRemoteService, BtPlayerService |
LDAC output side — encodes PCM and transmits via BlueZ |
hagoromo28 |
AudioInPlayerService, TunerPlayerService |
Audio input (line-in?) and FM tuner |
USB mode switching is driven by setprop sys.sony.config <mode> (per
init.usbcfg.rc); modes seen: adb, uac (USB Audio Class — i.e. USB DAC), msc (mass
storage), root/unroot. The uac path sets USB function = audio_func,adb and USB
product ID = 0x0B8C. None of these toggles touch Bluetooth.
HgrmMediaPlayerApp links against libc++.so.1 + libcxxrt.so.1 — confirming the
clang/LLVM + libc++ ABI, which is what baseline_v1.4.md §5.4 flagged as the toolchain
boundary for the C++ shim. Default ALSA via etc/asound.conf = hw:0,4 (the
cxd3778gf-icx-lowpower low-power playback device per Wampy ALSA.md).
The goal is now an engineering problem with a clear shape, not a research one. The replacement player needs to:
Step 1 — Don't enforce the block.
In the replacement player's QML/UI, do not show disconnectMsgOverlay when the user enters
USB-DAC mode, and do not call any BT-disconnect path. Sony's UI flow does both; ours
shouldn't. This step alone, without anything else, may already give a partial result on
device — worth verifying empirically (Phase E4/E5) before building more.
Step 2 — Bridge USB-DAC PCM into the BT transmit pipeline. Two viable approaches:
Approach A — drive the existing services directly.
- Instantiate
BtTransmitterServiceClientvia its factory. - Call
NotifyOpenAudio(),SetLdac(true),SetLdacSoundQuality(...). - Tap PCM from
UsbDeviceAudioPlayerService(either via its existing IPC, or by replacinglibaudiohal-uacalsasingletrack.sowith a build that writes to a different sink). - Push frames using whatever
pst::audiohal::AudioHalOutA2dpSnk's inverse looks like for the source direction. This needs Ghidra time onlibBtTransmitterService.soto find the PCM-write entry point — symbols visible so far are notification-only. - This is the clean approach but requires the C++ ABI shim (clang/libc++) per §5.4.
Approach B — ALSA loopback bridge.
- Build/insmod
snd_aloop.ko(kernel ALSA loopback module — would need a build matching the device kernel, 3.10.26-mt8590). - Reconfigure
etc/asound.confso the UAC path writes tohw:Loopback,0. - Run a small userspace daemon that reads
hw:Loopback,1and writes to BlueZ A2DP via a socket interface (or via the BlueZ-ALSA bridge if shipped/buildable on this device). - This sidesteps the C++ ABI issue (the bridge is pure C/Rust + ALSA + sockets) at the cost of a kernel module rebuild and an extra process in the audio path (~ few ms latency).
Approach A is architecturally cleaner; Approach B is more conservative and avoids touching
Sony's closed C++ surface. Pick after the device is in hand (Part E) — strace on
UsbDeviceAudioPlayerService and BtTransmitterService during stock USB-DAC mode will
make the choice obvious.
Step 3 — Latency expectation setting. Stock USB-DAC mode already has noticeable latency; LDAC adds ~150-200 ms. Stacking them makes the feature unusable for video/gaming but fine for music listening, which is the only sensible use case. The replacement player's UI for this mode should not advertise it as video-capable.
These are the questions host-side analysis cannot answer. Run these on the device after the Phase E0 wbrt backup:
- Does
BtTransmitterServiceacceptNotifyOpenAudio()whileUsbDeviceAudioPlayerServiceis also open? (i.e. is there any runtime mutex insideSoundServiceFwwe missed?) - What's the actual ALSA output device that
libaudiohal-uacalsasingletrackwrites to — confirmhw:0,4viacat /proc/asound/card0/pcm*/sub*/statusduring stock USB-DAC playback. - Does the BT A2DP source path have an ALSA-side entry point we can write PCM into (would
make Approach B trivial), or does it pull PCM from
SoundServiceFwover IPC only? - Confirm the
stracefinding frombaseline_v1.4.md §5.10: doesHgrmMediaPlayerAppactually calldisconnect/bluezpaths when entering USB-DAC mode, or is it purely the UI overlay that asks the user to do it?
Once these four are answered, the implementation is mechanical.