Skip to content

Commit

Permalink
Merge remote-tracking branch 'abrasive/1.0-dev' into 1.0-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
mrpippy committed Apr 3, 2013
2 parents a6f48e8 + 171e5d4 commit 66ccc1e
Show file tree
Hide file tree
Showing 10 changed files with 81 additions and 37 deletions.
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ ifdef CONFIG_AO
SRCS += audio_ao.c
endif

# default target
all: shairport

shairport: $(SRCS)
$(CC) $(CFLAGS) $(SRCS) $(LDFLAGS) -o shairport

clean:
rm shairport
rm -f shairport
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@ By [James Laird](mailto:[email protected]) ([announcement](http:https://mafipulatio

What it is
----------
This program emulates an AirPort Express for the purpose of streaming music from iTunes and compatible iPods. It implements a server for the Apple RAOP protocol.
This program emulates an AirPort Express for the purpose of streaming music from iTunes and compatible iPods and iPhones. It implements a server for the Apple RAOP protocol.
ShairPort does not support AirPlay v2 (video and photo streaming).

It supports multiple simultaneous streams, if your audio output chain (as detected by libao) does so.

How to use it
-------------
`perl shairport.pl`. See INSTALL.md for further information.
```
./configure
make clean all
./shairport -a 'AP Name'
```

The triangle-in-rectangle AirTunes (now AirPlay) logo will appear in the iTunes status bar of any machine on the network, or on iPod play controls screen. Choose your access point name to start streaming to the ShairPort instance.
The triangle-in-rectangle AirTunes (now AirPlay) logo will appear in the iTunes status bar of any machine on the network, or on iPod/iPhone play controls screen. Choose your access point name to start streaming to the ShairPort instance.

Thanks
------
Expand Down
8 changes: 6 additions & 2 deletions TODO
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
- makefile
- documentation
- PKGBUILD, initscript, systemd, launchd plist
- tidy debug printing
- alsa
- pipe
- avahi
- volume
- supervisor?
- pico mdns?
3 changes: 2 additions & 1 deletion audio_ao.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ static int init(int argc, char **argv) {

optind = 0;
// some platforms apparently require optreset = 1; - which?
char opt, *mid;
int opt;
char *mid;
while ((opt = getopt(argc, argv, "d:i:n:o:")) > 0) {
switch (opt) {
case 'd':
Expand Down
5 changes: 2 additions & 3 deletions common.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,9 @@ void warn(char *format, ...) {
va_end(args);
}

void debug(char *format, ...) {
if (!debuglev)
void debug(int level, char *format, ...) {
if (level > debuglev)
return;
fprintf(stderr, "DEBUG: ");
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
Expand Down
2 changes: 1 addition & 1 deletion common.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ typedef struct {
extern int debuglev;
void die(char *format, ...);
void warn(char *format, ...);
void debug(char *format, ...);
void debug(int level, char *format, ...);

uint8_t *base64_dec(char *input, int *outlen);
char *base64_enc(uint8_t *input, int length);
Expand Down
18 changes: 14 additions & 4 deletions player.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ void player_put_packet(seq_t seqno, uint8_t *data, int len) {

pthread_mutex_lock(&ab_mutex);
if (ab_buffering && buf_fill >= config.buffer_start_fill) {
debug("buffering over. starting play\n");
debug(1, "buffering over. starting play\n");
ab_buffering = 0;
pthread_cond_signal(&ab_buffer_ready);
}
Expand Down Expand Up @@ -302,10 +302,20 @@ static void bf_est_reset(short fill) {
}

static void bf_est_update(short fill) {
// the rate-matching system needs to decide how full to keep the buffer.
// the initial fill is present when the system starts to output samples,
// but most output chains will instantly gobble their own buffer's worth of
// data. we average for a while to decide where to draw the line.
if (fill_count < 1000) {
desired_fill += (double)fill/1000.0;
fill_count++;
return;
} else if (fill_count == 1000) {
// this information could be used to help estimate our effective latency?
debug(1, "established desired fill of %f frames, "
"so output chain buffered about %f frames\n", desired_fill,
config.buffer_start_fill - desired_fill);
fill_count++;
}

#define CONTROL_A (1e-4)
Expand All @@ -318,7 +328,7 @@ static void bf_est_update(short fill) {

bf_est_drift = biquad_filt(&bf_drift_lpf, CONTROL_B*(adj_error + err_deriv) + bf_est_drift);

debug("bf %d err %f drift %f desiring %f ed %f estd %f\n",
debug(3, "bf %d err %f drift %f desiring %f ed %f estd %f\n",
fill, bf_est_err, bf_est_drift, desired_fill, err_deriv, err_deriv + adj_error);
bf_playback_rate = 1.0 + adj_error + bf_est_drift;

Expand Down Expand Up @@ -401,12 +411,12 @@ static int stuff_buffer(double playback_rate, short *inptr, short *outptr) {
};
if (stuff) {
if (stuff==1) {
debug("+++++++++\n");
debug(2, "+++++++++\n");
// interpolate one sample
*outptr++ = dithered_vol(((long)inptr[-2] + (long)inptr[0]) >> 1);
*outptr++ = dithered_vol(((long)inptr[-1] + (long)inptr[1]) >> 1);
} else if (stuff==-1) {
debug("---------\n");
debug(2, "---------\n");
inptr++;
inptr++;
}
Expand Down
10 changes: 5 additions & 5 deletions rtp.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,15 @@ static void *rtp_receiver(void *arg) {
continue;
}
if (type == 0x56 && seqno == 0) {
debug("Suspected resync request packet received.\n");
player_flush();
debug(2, "resend-related request packet received, ignoring.\n");
continue;
}
debug(1, "Unknown RTP packet of type 0x%02X length %d seqno %d\n", type, nread, seqno);
}
warn("Unknown RTP packet of type 0x%02X length %d\n", type, nread);
}

debug("RTP thread interrupted. terminating.\n");
debug(1, "RTP thread interrupted. terminating.\n");
close(sock);

return NULL;
Expand Down Expand Up @@ -130,7 +130,7 @@ int rtp_setup(SOCKADDR *remote, int cport, int tport) {
if (running)
die("rtp_setup called with active stream!\n");

debug("rtp_setup: cport=%d tport=%d\n", cport, tport);
debug(1, "rtp_setup: cport=%d tport=%d\n", cport, tport);

// we do our own timing and ignore the timing port.
// an audio perfectionist may wish to learn the protocol.
Expand All @@ -149,7 +149,7 @@ int rtp_setup(SOCKADDR *remote, int cport, int tport) {

int sport = bind_port(remote);

debug("rtp listening on port %d\n", sport);
debug(1, "rtp listening on port %d\n", sport);

please_shutdown = 0;
pthread_create(&rtp_thread, NULL, &rtp_receiver, NULL);
Expand Down
53 changes: 39 additions & 14 deletions rtsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ static inline int rtsp_playing(void) {

static void rtsp_take_player(void) {
if (pthread_mutex_trylock(&playing_mutex)) {
debug("shutting down playing thread\n");
debug(1, "shutting down playing thread\n");
// XXX minor race condition between please_shutdown and signal delivery
please_shutdown = 1;
pthread_kill(playing_thread, SIGUSR1);
Expand Down Expand Up @@ -168,7 +168,7 @@ static int msg_handle_line(rtsp_message **pmsg, char *line) {
*pmsg = msg;
char *sp, *p;

debug("received request: %s\n", line);
debug(1, "received request: %s\n", line);

p = strtok_r(line, " ", &sp);
if (!p)
Expand Down Expand Up @@ -198,7 +198,7 @@ static int msg_handle_line(rtsp_message **pmsg, char *line) {
*p = 0;
p += 2;
msg_add_header(msg, line, p);
debug(" %s: %s\n", line, p);
debug(2, " %s: %s\n", line, p);
return -1;
} else {
char *cl = msg_get_header(msg, "Content-Length");
Expand Down Expand Up @@ -226,12 +226,12 @@ static rtsp_message * rtsp_read_request(int fd) {

while (msg_size < 0) {
if (please_shutdown) {
debug("RTSP shutdown requested\n");
debug(1, "RTSP shutdown requested\n");
goto shutdown;
}
nread = read(fd, buf+inbuf, buflen - inbuf);
if (!nread) {
debug("RTSP connection closed\n");
debug(1, "RTSP connection closed\n");
goto shutdown;
}
if (nread < 0) {
Expand Down Expand Up @@ -298,10 +298,10 @@ static void msg_write_response(int fd, rtsp_message *resp) {
"RTSP/1.0 %d %s\r\n", resp->respcode,
resp->respcode==200 ? "OK" : "Error");
write(fd, rbuf, nrbuf);
debug("sending response: %s", rbuf);
debug(1, "sending response: %s", rbuf);
int i;
for (i=0; i<resp->nheaders; i++) {
debug(" %s: %s\n", resp->name[i], resp->value[i]);
debug(2, " %s: %s\n", resp->name[i], resp->value[i]);
write(fd, resp->name[i], strlen(resp->name[i]));
write(fd, ": ", 2);
write(fd, resp->value[i], strlen(resp->value[i]));
Expand Down Expand Up @@ -368,6 +368,8 @@ static void handle_setup(rtsp_conn_info *conn,
sprintf(resphdr + strlen(resphdr), ";server_port=%d", sport);
msg_add_header(resp, "Transport", resphdr);

msg_add_header(resp, "Session", "1");

resp->respcode = 200;
}

Expand All @@ -376,6 +378,32 @@ static void handle_ignore(rtsp_conn_info *conn,
resp->respcode = 200;
}

static void handle_set_parameter(rtsp_conn_info *conn,
rtsp_message *req, rtsp_message *resp) {
if (!req->contentlength)
return;

char *cp = req->content;
int cp_left = req->contentlength;
char *next;
while (cp_left && cp) {
next = nextline(cp, cp_left);
cp_left -= next-cp;

if (!strncmp(cp, "volume: ", 8)) {
float volume = atof(cp + 8);
debug(1, "volume: %f\n", volume);
player_volume(volume);
} else {
debug(1, "unrecognised parameter: >>%s<< (%d)\n", cp, strlen(cp));
}
cp = next;
}


resp->respcode = 200;
}

static void handle_announce(rtsp_conn_info *conn,
rtsp_message *req, rtsp_message *resp) {

Expand All @@ -385,7 +413,7 @@ static void handle_announce(rtsp_conn_info *conn,
char *cp = req->content;
int cp_left = req->contentlength;
char *next;
while (cp) {
while (cp_left && cp) {
next = nextline(cp, cp_left);
cp_left -= next-cp;

Expand Down Expand Up @@ -446,7 +474,7 @@ static struct method_handler {
{"TEARDOWN", handle_teardown},
{"SETUP", handle_setup},
{"GET_PARAMETER", handle_ignore},
{"SET_PARAMETER", handle_ignore}, // XXX
{"SET_PARAMETER", handle_set_parameter}, // XXX
{"RECORD", handle_ignore},
{NULL, NULL}
};
Expand Down Expand Up @@ -484,11 +512,8 @@ static void apple_challenge(int fd, rtsp_message *req, rtsp_message *resp) {
#endif
{
struct sockaddr_in *sa = (struct sockaddr_in*)(&fdsa);
unsigned int ip = sa->sin_addr.s_addr;
for (i=0; i<4; i++) {
*bp++ = ip & 0xff;
ip >>= 8;
}
memcpy(bp, &sa->sin_addr.s_addr, 4);
bp += 4;
}

for (i=0; i<6; i++)
Expand Down
2 changes: 1 addition & 1 deletion shairport.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ void usage(char *progname) {
}

int parse_options(int argc, char **argv) {
char opt;
int opt;
while ((opt = getopt(argc, argv, "+hvp:a:o:b:")) > 0) {
switch (opt) {
default:
Expand Down

0 comments on commit 66ccc1e

Please sign in to comment.