Most of the times airplay client just streaming audio to sound card. What if we want to skip the current playing song without any operations on iTunes ?html
DACP solved this problem.git
Digital Audio Control Protocol (DACP) is a protocol used by the iTunes and other audio player and server applications on Mac, Windows and Linux computers.github
Acording to Unofficial AirPlay Protocol Specification. Airplay protocol includes a subset of DACP.c#
Send a HTTP request to iTunes DACP Server can pause the current playing song.app
GET /ctrl-int/1/pause HTTP/1.1 Host: starlight.local. Active-Remote: 1986535575
But, we need to find out the exact port of iTunes DACP Server and the value of Active-Remote
. They are hided in the shairport RTSP request header. RTSP is the protocol used in airplay audio streaming.tcp
Run shairport
with level 2 verbose mode, then you'll get all RTSP headers dumped.ide
$ ./shairport -vv .... received request: SET_PARAMETER rtsp://192.168.1.102/9487978813838695974 RTSP/1.0 RTP-Info: rtptime=2141729804 CSeq: 7 DACP-ID: 3F66DB0A16A7EBD6 Active-Remote: 2319864219 Content-Type: text/parameters Content-Length: 43 ....
About 10~20 RTSP headers will be dumped in first few seconds airplay get connected. Every RTSP request contains DACP-ID
and Active-Remote
fields. These fields will be used for DACP controlling later.this
mDNS is a service discovery protocol (SDP) like uPNP. Apple's Bonjour is based on mDNS.spa
Both iTunes and shairport uses mDNS to publish their services. When iTunes airplay device list menu is expanded, it searchs all airplay clients by mDNS discovery. When airplay is streaming, iTunes' DACP service is published.code
Avahi is an opensource mDNS implement. Use avahi-browse
command can find all shairport clients
= eth1 IPv4 6D2EDA9A5717@SugrCube_XXXX _raop._tcp local hostname = [none-4.local] address = [192.168.1.233] port = [5002] txt = ["md=0,1,2" "da=true" "pw=false" "txtvers=1" "vn=3" "sr=44100" "ss=16" "ch=2" "cn=0,1" "et=0,1" "ek=1" "sm=false" "tp=UDP"]
sr=44100 ss=16 ch=2
means audio is sample rate 44100, 16bit, 2 channel.
ONLY when shairport is running, iTunes DACP service can be discovered by avahi-browse
.
= eth1 IPv4 iTunes_Ctrl_816F839CE21BDC9B _dacp._tcp local hostname = [xb-2.local] address = [192.168.1.191] port = [50971] txt = []
In service name iTunes_Ctrl_816F839CE21BDC9B
. 816F839CE21BDC9B
is same as DACP-ID
in RTSP headers. DACP HTTP Request should be sent to 192.168.1.191:50971
.
Shairport doesn't save Active-Remote
or DACP-ID
by default, need to do some hacking.
in shairport rtsp.c: msg_handle_line()
, function handling RTSP Headers. Active-Remote
and DACP-ID
can be retrived:
char *active_remote = msg_get_header(msg, "Active-Remote"); char *dacp_id = msg_get_header(msg, "DACP-ID");
A patch for shairport is HERE.
Avahi is the best open source mDNS client & server so far. Both shairport and DACP client depend on it.
The making and deploying of avahi is complex. It depends on a f**king lot of libraries. In order to use libavahi-client:
enable-dbus=true
must be specified. --with-dbus-system-address
must be specified as same as libdbus's.system.d
directory. (according to this issue)Or in Ubuntu, there is no configuration at all ..
Here is a small DCAP Client written by Sugr team. It's a daemon running at UDP port 3391:
receives mDNS resolve command: Active-Remote
and DACP-ID
from shairport
receives iTunes control command: previtem
/ nextitem
form user
Paired with the hacked shairport, using nc
command send strings to UDP port 3391 can simply control current playing song.
# previous song echo -ne "previtem" | nc -u -4 localhost 3391 # next song echo -ne "nextitem" | nc -u -4 localhost 3391 # toggle between play and pause echo -ne "playpause" | nc -u -4 localhost 3391
Thanks to IV technology for technical discussing and sharing !