#include "filter.h"
#include "grab_client.cmdline.h"
#include "grab_client.h"
-#include "ringbuffer.h"
#include "error.h"
#include "audiod.h"
sa_time_diff_sign = 1, audiod_socket = -1;
static char *af_status, /* the audio format announced in server status */
*socket_name, *hostname;
-/** how many status items to remember */
-#define RINGBUFFER_SIZE 32
-static void *stat_item_ringbuf;
+static char *stat_item_values[NUM_STAT_ITEMS];
static FILE *logfile;
static const struct timeval restart_delay = {0, 300 * 1000};
-static struct audio_format_info afi[] = {
-
-[AUDIO_FORMAT_MP3] =
- {
- .write_cmd = "para_play",
- },
-[AUDIO_FORMAT_OGG] =
- {
- .write_cmd = "para_play",
- },
-};
+static struct audio_format_info afi[NUM_AUDIO_FORMATS];
static struct audiod_command cmds[] = {
{
/*
* log function. first argument is loglevel.
*/
-void para_log(int ll, char* fmt,...)
+void para_log(int ll, const char* fmt,...)
{
va_list argp;
FILE *outfd;
struct timeval now, diff, adj_stream_start, tmp;
int total = 0, use_server_time = 1;
- if (!playing)
- return make_message("%s:", length_seconds?
- "" : status_item_list[SI_PLAY_TIME]);
+ if (!playing) {
+ if (length_seconds)
+ return NULL;
+ return make_message("%s:", status_item_list[SI_PLAY_TIME]);
+ }
if (audiod_status == AUDIOD_OFF)
goto out;
if (sa_time_diff_sign > 0)
decoder_flags[MAX_STREAM_SLOTS] = '\0';
time_string = get_time_string(newest_stime);
uptime_string = uptime_str();
- ret = make_message("%s:%s\n%s:%s\n%s:%s\n%s",
+ ret = make_message("%s:%s\n%s:%s\n%s:%s",
status_item_list[SI_AUDIOD_UPTIME], uptime_string,
status_item_list[SI_DECODER_FLAGS], decoder_flags,
status_item_list[SI_AUDIOD_STATUS], audiod_status == AUDIOD_ON?
- "on" : (audiod_status == AUDIOD_OFF? "off": "sb"),
- time_string);
+ "on" : (audiod_status == AUDIOD_OFF? "off": "sb"));
+ if (time_string)
+ ret = make_message("%s\n%s", ret, time_string);
free(uptime_string);
free(decoder_flags);
free(time_string);
s->fci->error = 1;
}
+static void set_restart_barrier(int format, struct timeval *now)
+{
+ struct timeval tmp;
+
+ if (now)
+ tmp = *now;
+ else
+ gettimeofday(&tmp, NULL);
+ tv_add(&tmp, &restart_delay, &afi[format].restart_barrier);
+}
+
static void close_receiver(int slot_num)
{
struct slot_info *s = &slot[slot_num];
struct audio_format_info *a;
- struct timeval now;
if (s->format < 0 || !s->receiver_node)
return;
a->receiver->close(s->receiver_node);
free(s->receiver_node);
s->receiver_node = NULL;
- gettimeofday(&now, NULL);
- tv_add(&now, &restart_delay, &a->restart_barrier); /* FIXME: Use set_restart_barrier() */
+ set_restart_barrier(s->format, NULL);
}
static void kill_all_decoders(void)
}
}
-static void set_restart_barrier(int format, struct timeval *now)
-{
- struct timeval tmp;
-
- if (now)
- tmp = *now;
- else
- gettimeofday(&tmp, NULL);
- tv_add(&tmp, &restart_delay, &afi[format].restart_barrier);
-}
-
static void check_sigchld(void)
{
pid_t pid;
static void close_stat_pipe(void)
{
- char *msg;
int i;
if (stat_pipe < 0)
del_close_on_fork_list(stat_pipe);
stat_pipe = -1;
kill_all_decoders();
- for (i = 0; i < RINGBUFFER_SIZE; i++)
- ringbuffer_add(stat_item_ringbuf, para_strdup(NULL));
+ for (i = 0; i < NUM_STAT_ITEMS; i++) {
+ free(stat_item_values[i]);
+ stat_item_values[i] = NULL;
+ }
dump_empty_status();
length_seconds = 0;
offset_seconds = 0;
audiod_status_dump();
playing = 0;
- msg = make_message("%s:no connection to para_server\n",
+ stat_item_values[SI_STATUS_BAR] = make_message("%s:no connection to para_server\n",
status_item_list[SI_STATUS_BAR]);
- ringbuffer_add(stat_item_ringbuf, msg);
- stat_client_write(msg);
- free(msg);
+ stat_client_write(stat_item_values[SI_STATUS_BAR]);
}
static void __noreturn clean_exit(int status, const char *msg)
exit(status);
}
-static char *glob_cmd(char *cmd)
+__malloc static char *glob_cmd(char *cmd)
{
char *ret, *replacement;
struct timeval tmp, delay, rss; /* real stream start */
int ret, fds[3] = {1, -1, -1};
struct slot_info *s = &slot[slot_num];
struct audio_format_info *a = &afi[s->format];
- char *glob = glob_cmd(a->write_cmd);
+ char *glob = NULL;
- PARA_INFO_LOG("starting stream writer: %s\n", glob? glob : a->write_cmd);
+ if (a->write_cmd)
+ glob = glob_cmd(a->write_cmd);
+ if (!glob)
+ glob = para_strdup("para_play");
+ PARA_INFO_LOG("starting stream writer: %s\n", glob);
open_filters(slot_num);
-
- ret = para_exec_cmdline_pid(&s->wpid, glob? glob : a->write_cmd, fds);
+ ret = para_exec_cmdline_pid(&s->wpid, glob, fds);
free(glob);
if (ret < 0) {
PARA_ERROR_LOG("exec failed (%d)\n", ret);
if (!line)
return;
- ringbuffer_add(stat_item_ringbuf, line);
- stat_client_write(line);
itemnum = stat_line_valid(line);
- if (itemnum < 0)
+ if (itemnum < 0) {
+ PARA_WARNING_LOG("invalid status line: %s\n", line);
return;
+ }
+ stat_client_write(line);
+ free(stat_item_values[itemnum]);
+ stat_item_values[itemnum] = para_strdup(line);
ilen = strlen(status_item_list[itemnum]);
switch (itemnum) {
case SI_STATUS:
buf = &rn->buf;
len = &rn->loaded;
}
- PARA_DEBUG_LOG("writing %p (%d bytes)\n", *buf, *len);
+ PARA_DEBUG_LOG("writing %p (%zd bytes)\n", *buf, *len);
rv = write(s->write_fd, *buf, *len);
- PARA_DEBUG_LOG("wrote %d/%d\n", rv, *len);
+ PARA_DEBUG_LOG("wrote %d/%zd\n", rv, *len);
if (rv < 0) {
PARA_WARNING_LOG("write error in slot %d (fd %d): %s\n",
slot_num, s->write_fd, strerror(errno));
*len = 0;
s->fci->error = E_WRITE_AUDIO_DATA;
} else if (rv != *len) {
- PARA_DEBUG_LOG("partial %s write (%i/%i) for slot %d\n",
+ PARA_DEBUG_LOG("partial %s write (%i/%zd) for slot %d\n",
audio_formats[s->format], rv, *len, slot_num);
*len -= rv;
memmove(*buf, *buf + rv, *len);
if (ret < 0)
goto out;
PARA_INFO_LOG("%s -> default filter: %s\n", audio_formats[i], filters[j].name);
- ret = add_filter(i, "wav");
+ ret = add_filter(i, para_strdup("wav"));
if (ret < 0)
goto out;
PARA_INFO_LOG("%s -> default filter: wav\n", audio_formats[i]);
/*
* command handlers don't close their fd on errors (ret < 0) so that
* its caller can send an error message. Otherwise (ret >= 0) it's up
- * to each individual command to close the fd if necessary.
+ * to each individual command to close the fd if necessary.
*/
static int com_help(int fd, int argc, char **argv)
static int com_stat(int fd, __unused int argc, __unused char **argv)
{
int i, ret;
- char *buf = audiod_status_string();
+ char *buf = make_message("%s\n", audiod_status_string());
- buf = para_strcat(buf, "\n");
- for (i = RINGBUFFER_SIZE - 1; i >= 0; i--) {
- char *tmp, *line = ringbuffer_get(stat_item_ringbuf, i);
- if (!line)
- continue;
- tmp = make_message("%s\n", line);
- buf = para_strcat(buf, tmp);
- free(tmp);
+ for (i = 0; i < NUM_STAT_ITEMS; i++) {
+ char *tmp, *v = stat_item_values[i];
+ tmp = make_message("%s%s%s", buf, v? v : "", v? "\n" : "");
+ free(buf);
+ buf = tmp;
}
ret = client_write(fd, buf);
if (ret > 0)
static int open_stat_pipe(void)
{
int ret, fd[3] = {-1, 1, 0};
- char *argv[] = {BINDIR "/para_client", "stat", NULL};
pid_t pid;
- ret = para_exec(&pid, BINDIR "/para_client", argv, fd);
+ ret = para_exec_cmdline_pid(&pid, BINDIR "/para_client stat", fd);
if (ret >= 0) {
ret = fd[1];
PARA_NOTICE_LOG("stat pipe opened, fd %d\n", ret);
set_initial_status();
FOR_EACH_SLOT(i)
clear_slot(i);
- stat_item_ringbuf = ringbuffer_new(RINGBUFFER_SIZE);
init_grabbing();
setup_signal_handling();
if (conf.daemon_given)