X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/f5a03f58e65b08478c3eca469a88a763e2e187b9..ad9bae0b85165ad96e35c202c96e4adb67786a90:/server/speaker.c diff --git a/server/speaker.c b/server/speaker.c index 8acd9a6..407b1d7 100644 --- a/server/speaker.c +++ b/server/speaker.c @@ -1,6 +1,7 @@ /* * This file is part of DisOrder * Copyright (C) 2005, 2006, 2007 Richard Kettlewell + * Portions (C) 2007 Mark Wooding * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -68,6 +69,7 @@ #include #include #include +#include #include "configuration.h" #include "syscalls.h" @@ -77,6 +79,7 @@ #include "speaker-protocol.h" #include "user.h" #include "speaker.h" +#include "printf.h" /** @brief Linked list of all prepared tracks */ struct track *tracks; @@ -141,7 +144,7 @@ static void help(void) { /* Display version number and terminate. */ static void version(void) { - xprintf("disorder-speaker version %s\n", disorder_version_string); + xprintf("%s", disorder_version_string); xfclose(stdout); exit(0); } @@ -283,6 +286,17 @@ static void maybe_finished(void) { abandon(); } +/** @brief Return nonzero if we want to play some audio + * + * We want to play audio if there is a current track; and it is not paused; and + * it is playable according to the rules for @ref track::playable. + */ +static int playable(void) { + return playing + && !paused + && playing->playable; +} + /** @brief Play up to @p frames frames of audio * * It is always safe to call this function. @@ -293,15 +307,15 @@ static void maybe_finished(void) { * - If there is not enough audio to play then it play what is available. * * If there are not enough frames to play then whatever is available is played - * instead. It is up to mainloop() to ensure that play() is not called when - * unreasonably only an small amounts of data is available to play. + * instead. It is up to mainloop() to ensure that speaker_play() is not called + * when unreasonably only an small amounts of data is available to play. */ -static void play(size_t frames) { +static void speaker_play(size_t frames) { size_t avail_frames, avail_bytes, written_frames; ssize_t written_bytes; - /* Make sure there's a track to play and it is not pasued */ - if(!playing || paused) + /* Make sure there's a track to play and it is not paused */ + if(!playable()) return; /* Make sure the output device is open */ if(device_state != device_open) { @@ -340,8 +354,10 @@ static void play(size_t frames) { if(!playing->used || playing->start == (sizeof playing->buffer)) playing->start = 0; /* If the buffer emptied out mark the track as unplayably */ - if(!playing->used) + if(!playing->used && !playing->eof) { + error(0, "track buffer emptied"); playing->playable = 0; + } frames -= written_frames; return; } @@ -395,17 +411,6 @@ static const struct speaker_backend *backends[] = { 0 }; -/** @brief Return nonzero if we want to play some audio - * - * We want to play audio if there is a current track; and it is not paused; and - * it is playable according to the rules for @ref track::playable. - */ -static int playable(void) { - return playing - && !paused - && playing->playable; -} - /** @brief Main event loop */ static void mainloop(void) { struct track *t; @@ -465,15 +470,15 @@ static void mainloop(void) { /* We want to play some audio */ if(device_state == device_open) { if(backend->ready()) - play(3 * FRAMES); + speaker_play(3 * FRAMES); } else { /* We must be in _closed or _error, and it should be the latter, but we * cope with either. * - * We most likely timed out, so now is a good time to retry. play() - * knows to re-activate the device if necessary. + * We most likely timed out, so now is a good time to retry. + * speaker_play() knows to re-activate the device if necessary. */ - play(3 * FRAMES); + speaker_play(3 * FRAMES); } } /* Perhaps a connection has arrived */ @@ -527,9 +532,9 @@ static void mainloop(void) { error(0, "cannot play track because no connection arrived"); playing = t; /* We attempt to play straight away rather than going round the loop. - * play() is clever enough to perform any activation that is + * speaker_play() is clever enough to perform any activation that is * required. */ - play(3 * FRAMES); + speaker_play(3 * FRAMES); report(); break; case SM_PAUSE: @@ -543,7 +548,7 @@ static void mainloop(void) { paused = 0; /* As for SM_PLAY we attempt to play straight away. */ if(playing) - play(3 * FRAMES); + speaker_play(3 * FRAMES); } report(); break; @@ -558,8 +563,11 @@ static void mainloop(void) { playing = 0; } destroy(t); - } else + } else { + sm.type = SM_UNKNOWN; + speaker_send(1, &sm); error(0, "SM_CANCEL for unknown track %s", sm.id); + } report(); break; case SM_RELOAD: @@ -595,6 +603,7 @@ int main(int argc, char **argv) { static const int one = 1; struct speaker_message sm; const char *d; + char *dir; set_progname(argv); if(!setlocale(LC_CTYPE, "")) fatal(errno, "error calling setlocale"); @@ -629,18 +638,23 @@ int main(int argc, char **argv) { if(getuid() == 0 || geteuid() == 0) fatal(0, "do not run as root"); /* identify the backend used to play */ for(n = 0; backends[n]; ++n) - if(backends[n]->backend == config->speaker_backend) + if(backends[n]->backend == config->api) break; if(!backends[n]) - fatal(0, "unsupported backend %d", config->speaker_backend); + fatal(0, "unsupported api %d", config->api); backend = backends[n]; /* backend-specific initialization */ backend->init(); + /* create the socket directory */ + byte_xasprintf(&dir, "%s/speaker", config->home); + unlink(dir); /* might be a leftover socket */ + if(mkdir(dir, 0700) < 0 && errno != EEXIST) + fatal(errno, "error creating %s", dir); /* set up the listen socket */ 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", + snprintf(addr.sun_path, sizeof addr.sun_path, "%s/speaker/socket", config->home); if(unlink(addr.sun_path) < 0 && errno != ENOENT) error(errno, "removing %s", addr.sun_path);