Featured image of post Walkman 上手玩:给十年前的老玩意做个新 UI Part 1

Walkman 上手玩:给十年前的老玩意做个新 UI Part 1

前一阵子突然脑抽,想整一个 Walkman 回来玩玩,毕竟曾经也是 NW 系列 walkman 的忠实用户。拿到手之后,稍微搜索了一下发现社区对这个播放器已经有很多折腾的记录了,例如 Walkman One 固件,或者是一些 UI tweak。我自己呢其实一开始也没想到这玩意有啥可折腾的,到手之后装了个 Walkman One 固件之后就吃灰了,主要是非要拿个有线耳机确实不方便,而且 Walkman 的固件和 AirPods Pro 2 已经开始有兼容性问题: 连接上设备之后播放没有任何声音,无奈最后还是束之高阁。

中秋放假期间,我突然想起来自己还有这么个玩意,感觉放着心里痒痒用也派不上用场,掏出来看看我能拿来干些啥,突然发现这些自制固件是悄咪咪的把索尼留着的 adbd 激活了,这一下突然感觉就有意思了:当我拿到了 root shell,岂不是来去自如,想干嘛就干嘛!

先简单看看这个机器的基础信息吧:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ adb devices
List of devices attached
10453485000783	device

$ adb shell
# cat /proc/meminfo | head -n 3
MemTotal:         467984 kB
MemFree:           44644 kB
Buffers:           21532 kB

# cat /proc/cmdline
console=/dev/null root=/dev/ram vmalloc=496M slub_max_order=0 slub_debug=O  lcm=1-otm8018b_vdo_cmd fps=6023 vram=6291456 androidboot.selinux=disabled bootprof.pl_t=1145 bootprof.lk_t=2137 printk.disable_uart=0 boot_reason=4 icx_pm_helper.icx_sysinfo=0x00000000 icx_pm_helper.icx_modelid=0x20000007 mmc_core.emmc_boot_serial=0x96615529 icx_pm_helper.icx_boot_option=0 leds_drv.brightness=255 androidboot.serialno=10453485000783 androidboot.bootreason=wdt_by_pass_pwk icx_pm_helper.icx_boot_reason=0x1 androidboot.hardware=icx androidboot.console=ttyMT1 androidboot.printk=0 androidboot.bid3=1 

# cat /proc/cpuinfo
Processor	: ARMv7 Processor rev 3 (v7l)
...
Processor	: ARMv7 Processor rev 3 (v7l)
...

Hardware	: MT8590
Revision	: 0000
Serial		: 0000000000000000

# ls | tr '\n' ' '
bin boot boot.sh bootshow bootui build.prop cache contents contents_ext contents_ext1 data db default.prop dev emmc@android emmc@bootimg emmc@cache emmc@cm4 emmc@contents emmc@db emmc@dkb emmc@ebr1 emmc@expdb emmc@kb emmc@logo emmc@misc emmc@nvp emmc@nvram emmc@option1 emmc@option2 emmc@option3 emmc@pro_info emmc@protect_f emmc@protect_s emmc@recovery emmc@sec_ro emmc@seccfg emmc@tee1 emmc@tee2 emmc@uboot emmc@usrdata emmc@var emmc@xhrome etc factory file_contexts home init init.hagoromo.rc init.project.rc init.rc init.real init.usbcfg.rc init.usbcfgdmp.rc install_update_script lib newroot oem_cast_shlib opt1 opt2 opt3 proc res root sbin sys system tmp ueventd.audiodefault-b1.rc ueventd.audiodefault-b2.rc ueventd.audiodefault-b3.rc ueventd.icx.rc ueventd.rc usr var xbin

看起来是一个很常规的 Linux,但是带了一个非常 Android 风味的 rootfs。那么问题来了,如果我想在这个设备的屏幕上跑点什么,有什么办法可以做?

简单的搜索了一下发现其实社区已经有人做好了,就是 wampy:简单来说,索尼的播放器主程序 HgrmMediaPlayerApp 是个 Qt 应用,作者很讨巧的用上了 Qt eglfs 平台插件把自己的代码塞进这个进程,再通过 QWindow::hide() 把原窗口藏起来,屏幕就可以从索尼的进程中释放出来了。作者为了方便其他人用上他的成果,还准备了个 /tmp/wampy.sock 和 wampyctl 命令,给我们更容易的控制入口。

怎么跑的问题解决了,那么接下来需要想的就是跑点什么了。其实最开始我想到的是 DOOM,但是这玩意的小触摸屏玩 FPS 还是比较难以操作的(笑)。随后想到的就是另一个一次编写到处移植的经典老游戏:SDLPAL。

要让 SDLPAL 跑起来,首先要做的事让 SDL 在这个平台上能用。如果想正儿八经的让 SDL 移植过来,需要走的路线是 SDL video driver,对于这个折腾来说其实就有点划不来了。但是根据 wampy 画磁带的方案我们能看到,实际上想让内容到屏幕上出来,可以直接在内存里弄一个 bitmap 当作纹理,也就是说,我们完全可以直接走纯 CPU 的 SDL 运行模式,把所有的画面都塞进一个 480x800 的 SDL_Surface,最后用 eglSwapBuffers 把纹理画到屏幕上即可。为了验证这条思路,我直接让 DSH 开始上手编码啊(老实写代码,很枯燥吧),很顺利的就完成了基础图形的验证:

显示问题解决了接下来要做的就不多了,接着让 AI 来做触屏和按键的支持,编译方面 SDL2 静态交叉编译用 zig:-target arm-linux-gnueabihf.2.23,再把自己库存的游戏资源放到机器里,游戏就水灵灵的跑起来了~

群友:好hifi的敲脑袋

群友:好听才是好头

当然整个过程其实并没有这么顺利,还是踩了很多坑的,这里简单的列举一下遇到的问题和解决方案,具体的细节已经记不太清了,我直接让 AI 归纳了一下:

  • 事件没用:往 SDL 队列里塞 SDL_KEYDOWN 没反应,SDLPAL 判断输入走的是 SDL_GetKeyboardState() 轮询,得直接改键盘状态。
  • 按键穿透:hide 只是不画索尼窗口,KeyService 还在读同一个 evdev,按播放键游戏没动、MP3 倒是开始放了 → EVIOCGRAB 独占 event0/1/4。
  • 红蓝对调:SDL_PIXELFORMAT_ARGB8888 在小端内存里是 BGRA,按 GL_RGBA 上传就反了 → 换 RGBA32。
  • 触摸不准:上报范围是 0..959 × 0..1599,不是 480×800,所以帮助面板上的红点跟手指完全无关。
  • 声卡归谁:SDL 的 ALSA 后端在交叉编译时没真编进去,走内核 OSS 兼容层 AUDIODEV=/dev/snd/dsp;索尼在放歌时先让它 pause,抢不到就静音继续。

做到这里我突然有了一个很大胆甚至点狂妄的想法:其实我觉得索尼的系统并没有那么好用,既然现在有 AI 神力加持,同时我自己对 Linux 和音频 codec 相关不说精通,至少方方面面都有点了解,那么我是不是可以带着 LLM,做出一个更满足我个人偏好的用户态播放器呢?

comments powered by Disqus
Except where otherwise noted, content on this blog is licensed under CC-BY 2.0.
Built with Hugo
Theme Stack designed by Jimmy