Background
In android_apps_and_system_configuration_notes(37) it was found that the default music player for on Android is insufficient when dealing with music collections organized as directory trees.
Auxio was found to be a viable player although (like with most GUI players) the playlist management in Auxio is easy to fat-finger and also, the usage of a huge (~4000 entries pre-generated) playlist created using a modified variant of gmusicradio(32) was probably not the best solution to address the need for a nice music experience on the go.
A lot of insight regarding local music playback on a proper PC was gained during the development of gmusicradio(32) and then maenmpc(32).
Scrobbling (in theory) permits accumulating play counts from multiple devices.
MAENMPC was designed in a way that the essential components (radio, podcast, scrobble) could all run independently of the main application. The backend MPD server is also quite a portable component to the extent that there are multiple ways to setup a local MPD server on an Android phone. Also, multiple clients are available for smartphone or “responsive” webbrowser usage making them well-suited for running on smartphones.
Overview
Many of the building blocks which were already there allow for a nice music playback experience on a PC may be run on Android phones. Additional components and glue code fill in the need for a different user interface and allow for the offline collection of play counts such that the sum of all play counts can be tracked in a central Maloja instance.
This page describes my particular setup for music listening on the smartphone and explains some of the difficulties I encountered alongside the way.
Assumptions
- 512 GiB µSD card (or other large-enough size) holds the offline music collection on the smartphone.
- The smartphone is assumed not to be always online.
- The operating system is Android with Termux (Debian-like shell in an “App”) is installed.
- The presence of an SSH daemon on Termux is assumed (you could install it any time if you don’t have it yet, but the setup for it is not described here)
- The source of truth regarding play counts and ratings is stored on the Maloja and MPD servers on a (non-mobile) PC
Block Diagram
╔═══════════════════════════════════════════════╗ ╔═══════════════════╗
║ Smartphone ║ ║ PC ║
║ ║ ║ ║
║ ┌───────────────────────────────────────────┐ ║ ║ runs services ║
║ │ Termux runs Services │ ║ ║ Maloja port 42010 ║
║ │ │ ║ ║ MPD port 6600 ║
║ │ ┌─────────────────┐ │ ║ ║ ║
║ │ │ sshd port 8022 ◀───────────────┼─╫──╢ exchanges ║
║ │ └─────────────────┘ │ ║ ║ files ║
║ │ │ ║ ║ ║
║ │ ┌─────────────────┐ │ ║ ╚═══════════════════╝
║ │ │ mpd port 6600 │ │ ║
║ │ └────▲────────▲───┘ │ ║
║ │ │ │ │ ║
║ │ ┌────────────┴────┐ ┌─┴─────────────────┐ │ ║
║ │ │ mympd port 8080 │ │ maenmpc │ │ ║
║ │ └────────────▲────┘ │ (radio, scrobble) │ │ ║
║ │ │ └───────────────────┘ │ ║
║ │ │ │ ║
║ └──────────────┼────────────────────────────┘ ║
║ │ ║
║ ┌──────────────┴────┐ ║
║ │ Webbrowser │ ║
║ │ accesses myMPD │ ║
║ └───────────────────┘ ║
╚═══════════════════════════════════════════════╝
Key Ideas
- Setup an MPD server on the smartphone
- Export the state of Maloja+MPD from the PC to the smartphone into a table of stickers such that Maloja need not run on the smartphone. Only MPD is needed there.
- Run MAENMPC non-interactively on the smartphone for playlist generation and scrobble keeping in a file
- Download this file to the PC and import it into Maloja to synchronize the play counts originating from the phone
- To play back music on the phone, use the myMPD client as an user interface (MAENMPC is ill-suited to phone usage due to its keyboard-centric design)
Setup an MPD Server on the Smartphone
There are multiple broad ways to go about MPD on the smartphone:
- Run the server elsewhere and stream music to the phone. This requires a working online connection and is thus out of scope for this article.
- Install MPD using an app. E.g. from here: https://f-droid.org/en/packages/org.musicpd/
- Install MPD in Termux, i.e. with
pkg install mpd
In principle, I think option 2 is the best because it makes sense for the music playback application to run “as natively as possible”. However, there are practical constraints when using the Android app: The config is harder to edit (cf. e.g. https://github.com/MusicPlayerDaemon/MPD/issues/1594) and also it seems that a stickers database cannot easily be configured?
As a result, I chose to go with option 3 and installed MPD through Termux.
As a preliminary to running the daemon, the following directories should be created:
mkdir -p wd/mpd/playlists
Inside wd/mpd
, create mpd.conf
as
follows:
music_directory "/storage/3BD7-948E/masysma/music2"
playlist_directory "/data/data/com.termux/files/home/wd/mpd/playlists"
db_file "/data/data/com.termux/files/home/wd/mpd/tag_cache"
state_file "/data/data/com.termux/files/home/wd/mpd/state"
sticker_file "/data/data/com.termux/files/home/wd/mpd/sticker.sql"
bind_to_address "127.0.0.1"
port "6600"
restore_paused "yes"
auto_update "yes"
input {
plugin "file"
enabled "yes"
}
decoder {
plugin "flac"
enabled "yes"
}
decoder {
plugin "mad"
enabled "yes"
}
# https://www.reddit.com/r/mpd/comments/r9mgr0/android_audio_output_settings/
audio_output {
type "sles"
name "OpenSL ES audio output"
}
replaygain "album"
filesystem_charset "UTF-8"
Here, the music_directory
must be adjusted to the local
Termux storage. Apart from that it is a pretty standard MPD config. The
only hard part may be identifying the audio output. I copied this from
the given source without further questioning. There may be better ways
to go about it, but this seems to work OK for now.
To ensure that MPD is always started when opening Termux, add the
following lines inside .bashrc
:
if [ -n "$PS1" ]; then
# 127.0.0.1:6600
pidof mpd || mpd $HOME/wd/mpd/mpd.conf
fi
Export the State of Maloja+MPD to the Smartphone
Using maenmpc(32), it is straight-forward to export the data from the PC and copy them to the smartphone:
maenmpc -export-stickers /tmp/sticker.sql
scp /tmp/sticker.sql u0_a162@192.168.1.102:/data/data/com.termux/files/home/wd/mpd
Adjust the username and IP address to your needs. In my case, it was not necessary to stop MPD during the transmission of the new file. However, it may be necessary to restart the radio service to pickup updated stats.
Run MAENMPC on a Smartphone
Although it is certainly possible to do this all from the phone screen, I suggest to run the commands over SSH.
Download build tool
rebar3
Note that the erlang-related commands (bootstrap
,
rebar3
) can take quite a long while without printing
anything on the screen. Stand by and be patient…
pkg install erlang
cd wd
git clone https://github.com/erlang/rebar3.git
cd rebar3
./bootstrap
./rebar3 local install
cd ../..
export PATH=/data/data/com.termux/files/home/.cache/rebar3/bin:$PATH
Download and build
maenmpc
cd wd
git clone https://github.com/m7a/lo-maenmpc.git
cd lo-maenmpc
Comment-in the following lines in rebar3.config
:
{deps, [
{cecho, {git, "https://github.com/m7a/cecho.git", {branch, "masysma_patches"}}},
{erlmpd, {git, "https://github.com/m7a/bo-erlmpd.git", {branch, "master"}}},
{sqlite3, {git, "https://github.com/processone/erlang-sqlite3.git", {branch, "master"}}},
{jiffy, {git, "https://github.com/davisp/jiffy.git", {branch, "master"}}}
]}.
This allows the next step to download these as dependencies. This is easier on the phone compared to installing MAENMPC using Debian packages.
rebar3 release
In order to run MAENMPC through the scripts generated by
rebar3
, I had to disable the Termux logger which I did by
the following hack:
mv /data/data/com.termux/files/usr/bin/logger /data/data/com.termux/files/usr/bin/logger.bak
I configured MAENMPC according to my setup as follows:
[{maenmpc, [
{mpd, [
{local, [{ip, {"127.0.0.1", 6600}}]}
]},
{alsa, "/proc/asound/RAVENNA/pcm0p/sub0/hw_params"},
{primary_ratings, local},
{radio, #{
schedule_len => 60,
chaos_factor => 2.0,
initial_factor => 0.5,
min_good_perc => 30,
default_rating => 60,
discard_prefix => <<"epic/">>
}},
{maloja, [
{primary_albumart, local},
{scrobble_send, true},
{scrobble_file, "scrobble_test.txt"}
]},
{podcast, #{
% [...] leave this part at the default
mpd => [
{local, [
% [...] leave this part at the default
]}
]
}}
]}].
Some things like alsa
and podcast
are not
used with the smartphone setup, hence they can stay at the default
values. Note that no Maloja server is configured and instead, play
counts are configured to be recorded in a file called
scrobble_test.txt
. By leaving out the Maloja credentials,
MAENMPC automatically attempts to retrieve play count information from
the playCount
sticker for radio play-list generation
usage.
While it may not make sense to properly install MAENMPC on
the smartphone, it may still make sense to create a shortcut. To do
this, I created a script maenmpcd
in the Termux home
directory with the following contents:
#!/bin/sh -exu
cd "$HOME/wd/lo-maenmpc"
exec ./_build/default/rel/maenmpc/bin/maenmpc foreground -radio -scrobble
This includes the commandline used to run the radio and scrobble services through MAENMPC. As already mentioned, interactive usage may be possible but does not seem worthwhile on a smartphone screen.
Download Scrobbles from Smartphone and Import on PC
Again, adjust the SSH commandline to your setup and run the following on the PC:
scp u0_a162@192.168.1.102:/data/data/com.termux/files/home/wd/lo-maenmpc/_build/default/rel/maenmpc/scrobble_test.txt /tmp/scrobbles.txt
maenmpc -import-scrobbles /tmp/scrobbles.txt
ssh u0_a162@192.168.1.102 rm /data/data/com.termux/files/home/wd/lo-maenmpc/_build/default/rel/maenmpc/scrobble_test.txt
Setup myMPD on the Smartphone
Install the myMPD package in Termux:
pkg install mympd
Create the MPD cache directory and let it establish its base config files:
mkdir -p /data/data/com.termux/files/usr/var/cache/mympd
mympd -c
Edit the configuration in directory
/data/data/com.termux/files/usr/var/lib/mympd/config
. I
changed the following settings:
Key | Value |
---|---|
http_host |
localhost |
http_port |
8080 |
ssl |
false |
Afterwards, add myMPD to the applications to be started from
.bashrc
:
if [ -n "$PS1" ]; then
# 127.0.0.1:8080
pidof mympd || mympd &
fi
To check that it is working without fiddling with the smartphone, redirect port 8080 from the smartphone to localhost 8089 and open that address in the web browser:
ssh -L 127.0.0.1:8089:127.0.0.1:8080 192.168.1.102
Copying the Music to the Phone
So far, the article blindly assumes the music to be readily present on the smartphone. In case you wonder about how to put it there in the first place, there are two basic ways to go about it:
- Copy the local music collection files 1:1 to the phone
- Resample local music collection to 48kHz (Android’s chosen samplerate…) and copy the result to the phone.
In case you are interested in the latter approach, a Makefile crafted for this purpose can be found in the MAENMPC repository at https://github.com/m7a/lo-maenmpc/blob/master/aux/resample_copy_to_sshfs.mk.
Its basic assumption is that subdirectory album
contains
albums which need to be processed in one batch each as to allow for
album-centric loudgain values to be computed. The remainder of
subdirectories (single
, epic
,
track
) is all processed on a file-by-file basis.
Future Directions
Preliminary testing was successful. It remains to be seen how heavy this huge music playback setup (MAENMPC takes > 100 MiB of RAM on the phone thanks to keeping a copy of the database in RAM) is on the smartphone battery and whether the usage with a combination of server software inside Termux and a client in the smartphone webbrowser works well enough for casual mobile usage.
See Also
Internal Links
- android_apps_and_system_configuration_notes(37)
- more general notes about my Android setup
- maenmpc(32) - Portable console-based MPD client
Helpful Programs
- Auxio https://f-droid.org/en/packages/org.oxycblt.auxio/ - Music Player on Android (standalone, without all the MPD complexity)
- Termux https://termux.dev/en/ - Linux shell for Android
- myMPD https://jcorporation.github.io/myMPD/ - Portable web-based MPD client