I was bored today and the internet was broken so rather than going outside or exercising or something like that I tried to figure out how to remotely control XMMS. It was an interesting project that touched on a couple different areas of system configuration useful otherwise, so I figured I'd record the process.
I've got a Madrake box that has speakers, but which sits across the lab from the RedHat 9 server where I do my work. I want to be able to change songs and pause it when someone comes in without getting up.
There is a useful program under Mandrake called
xmms-shell
that lets me do the normal forward and
back that I can do using the xmms program directly, but also
select specific entries in the playlist and load playlists and
different things.
It is a neat program and I wondered how it worked, so I ran
strace xmms-shell
to see. When I do a jump
10
I see a trace like this:
brk(0x807e000) = 0x807e000 socket(PF_UNIX, SOCK_STREAM, 0) = 3 getuid32() = 503 geteuid32() = 503 setuid32(0x1f7) = 0 setreuid32(0x1f7, 0x1f7) = 0 connect(3, {sin_family=AF_UNIX, path="/tmp/xmms_will.0"}, 110) = 0 write(3, "\1\0\t\0\0\0\0\0", 8) = 8 read(3, "\1\0\0\0\4\0\0\0", 8) = 8 read(3, "c\0\0\0", 4) = 4 read(3, "\1\0\0\0\0\0\0\0", 8) = 8 close(3) = 0 socket(PF_UNIX, SOCK_STREAM, 0) = 3 getuid32() = 503 geteuid32() = 503 setuid32(0x1f7) = 0 setreuid32(0x1f7, 0x1f7) = 0 connect(3, {sin_family=AF_UNIX, path="/tmp/xmms_will.0"}, 110) = 0 write(3, "\1\0\10\0\4\0\0\0", 8) = 8 write(3, "\t\0\0\0", 4) = 4 read(3, "\1\0\0\0\0\0\0\0", 8) = 8 close(3) = 0 write(1, "Jumped to position 10 in the pla"..., 39Jumped to position 10 in the playlist.) = 39
It turns out that the important lines are these two:
write(3, "\1\0\10\0\4\0\0\0", 8) = 8 write(3, "\t\0\0\0", 4) = 4
The following perl code will cause xmms to jump to a song:
#!/usr/bin/perl use strict; use Socket; my $path = "/tmp/xmms_will.0"; my $num = shift || die "enter num"; socket(XMMS, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!"; connect(XMMS, sockaddr_un($path)) or die "open: $path: $!"; syswrite(XMMS, "\1\0\10\0\4"); syswrite(XMMS, pack("C4", $num - 1)); close(XMMS);
I could go through and reverse engineer the codes for each command and write little scripts like the one above. This would be time consuming though and if the program changed versions the codes could well change.
Another option is to use the xmms-shell program which can take
scripts on the command line like xmms-shell -e "jump
23"
. I like this idea more since it is more likely to last
over time. The one drawback is xmms-shell isn't widley
distributed and so it wouldn't work on other systems.
I think the idea I like the best is doing it programatically.
XMMS includes functions that can be seen with nm
/usr/lib/libxmms.a | grep remote
. Calling those functions
without writing a C program is a bit of a pain though. I think I
want to do the interface through a scripting language...
Unfortunately the computer I am working on has no development
tools at all installed, so even though I there is a XMMS
interface module for perl, when I do perl -MCPAN -e
'install xmms'
it fails because there is no C compiler and
none of the header files for perl.
Because my goal was to do as few modifications as possible to the box I will stich with xmms-shell.
The setup that I want is to have my numeric keypad work in bash like it does for winamp. That is:
7 seek backward 5 seconds not
possible with xmms-shell |
8 increase volume
5% upvoulme |
9 seek forward 5 seconds not
possible with xmms-shell |
4 next song next (only possible
to do next song in order; no shuffle) |
5 play play |
6 previous song next (only
possible to do previous song in order; no shuffle) |
1 |
2 decrease volume
5% downvolume |
3 |