Hiby R3 Pro

Bought this player to replace a Pioneer XDP-30R I didn’t like much (which replaced a Cowon J3 which I liked very much - physical buttons, OLED display and 60 hour battery life is still unbeatable). A nice little DAP with an incredibly annoying bug (by design).

Sorting bug

If you’ve used this player with non-ASCII (and non-Chinese) song metadata, you’ve probably noticed that the sort order is rather strange. I’m seeing:

A
B
八
C
誠
虫
初
D

The ASCII titles are in order, but other stuff is mixed in between. The usual sorting for Japanese would put the ASCII set together at the top before going through other character sets. Pulling out the database (/data/usrlocal_media.db, not accessible normally) it’s an sqlite file. The album tables are

CREATE TABLE ALBUM_TABLE(id INT, album TEXT COLLATE NOCASE,character TEXT COLLATE NOCASE, cn INT, ctime INT, mtime INT, mqa INT, pinyin_charater TEXT, PRIMARY KEY(album));
CREATE TABLE ALBUM2_TABLE(id INT,album TEXT COLLATE NOCASE,character TEXT COLLATE NOCASE, cn INT, ctime INT, mtime INT, mqa INT, pinyin_charater TEXT,  PRIMARY KEY(album));

Selecting a few entries out of ALBUM_TABLE showed the same ordering as the weird listing in the UI; ALBUM2_TABLE didn’t have any immediately obvious ordering. They both had the same number of entries. Thinking that the UI was using the unsorted output out of the database, I fixed the sorting:

CREATE TABLE ALBUM_TABLE2(id INT, album TEXT COLLATE NOCASE,character TEXT COLLATE NOCASE, cn INT, ctime INT, mtime INT, mqa INT, pinyin_charater TEXT, PRIMARY KEY(album));
CREATE TABLE ALBUM2_TABLE2(id INT,album TEXT COLLATE NOCASE,character TEXT COLLATE NOCASE, cn INT, ctime INT, mtime INT, mqa INT, pinyin_charater TEXT,  PRIMARY KEY(album));

INSERT INTO ALBUM_TABLE2(id, album, character, cn, ctime, mtime, mqa, pinyin_charater)
SELECT id, album, character, cn, ctime, mtime, mqa, pinyin_charater FROM ALBUM_TABLE
ORDER BY album;

INSERT INTO ALBUM2_TABLE2(id, album, character, cn, ctime, mtime, mqa, pinyin_charater)
SELECT id, album, character, cn, ctime, mtime, mqa, pinyin_charater FROM ALBUM2_TABLE
ORDER BY album;

DROP TABLE ALBUM_TABLE;
DROP TABLE ALBUM2_TABLE;

ALTER TABLE ALBUM_TABLE2 RENAME TO ALBUM_TABLE;
ALTER TABLE ALBUM2_TABLE2 RENAME TO ALBUM2_TABLE;

And put the database back into the player. This fixed the ordering in the UI, but this is annoying to do everytime the database gets updated.

Out of curiousity I pulled the strings from the hiby_player binary and found:

SELECT * FROM ALBUM_TABLE limit ? offset ?
SELECT * FROM ARTIST_TABLE limit ? offset ?
SELECT * FROM GENRE_TABLE limit ? offset ?

Which corroborates my theory. At first I thought the player was doing a weird sort in memory and writing out to the database in that order, but the 2nd table seemed out of place - wouldn’t it be easier to write everything to the database on the first pass then get the database to re-order it? Another look into the strings, and:

INSERT INTO ALBUM_TABLE SELECT * FROM ALBUM2_TABLE ORDER BY album COLLATE pinyin

I haven’t disassembled the hiby_player binary to check but it seems logical. So, the fix is to open up the binary and null out the ‘COLLATE pinyin’ bits. It looks like this isn’t actually a bug - the developers set it to sort for Chinese and ignored everyone else.

Along the way I also fixed the misspelt VORBIS (VOROIS) because it bugs me.

Modifying the firmware

The update blob is an ISO9660 image. The SYSTEM.UBI file inside is a ubifs image - mount using nandsim and the ubi tools. Some scripts are available on github.

The image can be built using the same command as the Shanling M2:

mkfs.ubifs -e 1x1f000 -c 1024 -m 0x800

Fix the md5sum in UPDATE.TXT, repack with genisoimage (doesn’t seem to need any particular arguments) and reflash. Be aware that the updater seems to require a certain pattern of blank lines - if updates are failing, check that first.

If you’re concerned about the correct parameters to make the image, the output of mtdinfo is:

mtd4
Name:                           rootfs
Type:                           nand
Eraseblock size:                131072 bytes, 128.0 KiB
Amount of eraseblocks:          512 (67108864 bytes, 64.0 MiB)
Minimum input/output unit size: 2048 bytes
Sub-page size:                  2048 bytes
OOB size:                       64 bytes
Character device major/minor:   90:8
Bad blocks are allowed:         true
Device is writable:             true

Recovery

I haven’t verified this procedure! But in theory, it’s possible. Hiby provided a recovery restoration procedure for R3 Pro/Pro Saber units that had something missing from the flash. We know the CPU is an Ingenic X1000E, using that tool (Cloner) or ingenic-boot it should be possible to reflash the system partition. Holding the ‘song back’ (top) button while booting gets into the Xburst bootloader. On the other hand, a UBI flash image is not a raw flash image so it may not go smoothly.