/*
* This file is part of DisOrder
- * Copyright (C) 2005-2010 Richard Kettlewell
+ * Copyright (C) 2005-2013 Richard Kettlewell
* Portions (C) 2007 Mark Wooding
*
* This program is free software: you can redistribute it and/or modify
return;
memset(&sm, 0, sizeof sm);
sm.type = paused ? SM_PAUSED : SM_PLAYING;
- strcpy(sm.id, playing->id);
+ strcpy(sm.u.id, playing->id);
sm.data = playing->played / (uaudio_rate * uaudio_channels);
speaker_send(1, &sm);
xtime(&last_report);
static size_t speaker_callback(void *buffer,
size_t max_samples,
void attribute((unused)) *userdata) {
- const size_t max_bytes = max_samples * uaudio_sample_size;
+ size_t max_bytes = max_samples * uaudio_sample_size;
size_t provided_samples = 0;
+ /* Be sure to keep the amount of data in a buffer a whole number of frames:
+ * otherwise the playing threads can become stuck. */
+ max_bytes -= max_bytes % (uaudio_sample_size * uaudio_channels);
+
pthread_mutex_lock(&lock);
/* TODO perhaps we should immediately go silent if we've been asked to pause
* or cancel the playing track (maybe block in the cancel case and see what
/* Limit to what we were asked for */
if(bytes > max_bytes)
bytes = max_bytes;
+ /* And truncate to a whole number of frames. */
+ bytes -= bytes % (uaudio_sample_size * uaudio_channels);
/* Provide it */
memcpy(buffer, playing->buffer + playing->start, bytes);
playing->start += bytes;
}
/* Notify the server that the connection arrived */
sm.type = SM_ARRIVED;
- strcpy(sm.id, id);
+ strcpy(sm.u.id, id);
speaker_send(1, &sm);
}
} else
if(pending_playing)
disorder_fatal(0, "got SM_PLAY but have a pending playing track");
}
- t = findtrack(sm.id, 1);
+ t = findtrack(sm.u.id, 1);
D(("SM_PLAY %s fd %d", t->id, t->fd));
if(t->fd == -1)
disorder_error(0,
force_report = 1;
break;
case SM_CANCEL:
- D(("SM_CANCEL %s", sm.id));
- t = removetrack(sm.id);
+ D(("SM_CANCEL %s", sm.u.id));
+ t = removetrack(sm.u.id);
if(t) {
if(t == playing || t == pending_playing) {
/* Scratching the track that the server believes is playing,
* log more because there's been a bug here recently than because
* it's particularly interesting; the log message will be removed
* if no further problems show up. */
- disorder_info("SM_CANCEL for nonplaying track %s", sm.id);
+ disorder_info("SM_CANCEL for nonplaying track %s", sm.u.id);
sm.type = SM_STILLBORN;
}
- strcpy(sm.id, t->id);
+ strcpy(sm.u.id, t->id);
destroy(t);
} else {
/* Probably scratching the playing track well before it's got
* going, but could indicate a bug, so we log this as an error. */
sm.type = SM_UNKNOWN;
- disorder_error(0, "SM_CANCEL for unknown track %s", sm.id);
+ disorder_error(0, "SM_CANCEL for unknown track %s", sm.u.id);
}
speaker_send(1, &sm);
force_report = 1;
disorder_error(0, "cannot read configuration");
disorder_info("reloaded configuration");
break;
+ case SM_RTP_REQUEST:
+ /* TODO the error behavior here is really unhelpful */
+ if(rtp_add_recipient(&sm.u.address))
+ disorder_error(0, "unacceptable RTP destination");
+ break;
+ case SM_RTP_CANCEL:
+ if(rtp_remove_recipient(&sm.u.address))
+ disorder_error(0, "unacceptable RTP destination for removal");
+ break;
default:
disorder_error(0, "unknown message type %d", sm.type);
}
&& playing->used <= early_finish) {
memset(&sm, 0, sizeof sm);
sm.type = SM_FINISHED;
- strcpy(sm.id, playing->id);
+ strcpy(sm.u.id, playing->id);
speaker_send(1, &sm);
playing->finished = 1;
}
/* backend-specific initialization */
if(backend->configure)
backend->configure();
+ uaudio_set("application", "disorder-speaker");
backend->start(speaker_callback, NULL);
- /* create the socket directory */
- byte_xasprintf(&dir, "%s/speaker", config->home);
+ /* create the private socket directory */
+ byte_xasprintf(&dir, "%s/private", config->home);
unlink(dir); /* might be a leftover socket */
if(mkdir(dir, 0700) < 0 && errno != EEXIST)
disorder_fatal(errno, "error creating %s", dir);
listenfd = xsocket(PF_UNIX, SOCK_STREAM, 0);
memset(&addr, 0, sizeof addr);
addr.sun_family = AF_UNIX;
- snprintf(addr.sun_path, sizeof addr.sun_path, "%s/speaker/socket",
+ snprintf(addr.sun_path, sizeof addr.sun_path, "%s/private/speaker",
config->home);
if(unlink(addr.sun_path) < 0 && errno != ENOENT)
disorder_error(errno, "removing %s", addr.sun_path);
disorder_fatal(errno, "error binding socket to %s", addr.sun_path);
xlisten(listenfd, 128);
nonblock(listenfd);
+ disorder_info("version "VERSION" process ID %lu",
+ (unsigned long)getpid());
disorder_info("listening on %s", addr.sun_path);
memset(&sm, 0, sizeof sm);
sm.type = SM_READY;