PACKAGE_VERSION := @PACKAGE_VERSION@
M4 := @M4@
+LOPSUBGEN := @LOPSUBGEN@
executables := @executables@
NEWS
====
-
---------------------
current master branch
---------------------
- New sort order for the ls command: -s=h sorts the ls output by hash
value of the audio file.
+- autogen.sh now runs the test suite after a successful build.
- The contents of overview.pdf have been integrated into the user
manual.
+- Fixed sized audio format headers for ogg/opus streams.
- The doxygen source browser has been disabled temporarily. The
API reference is still online, though.
- Overhaul of the source code documentation.
+- The deprecated --full-path option of the ls command has been
+ removed. It was a no-op since 0.6.0.
+- The wma decoder has been cleaned up and its bitstream API made
+ more robust.
+- The image/lyrics ID status items of the current audio file are now
+ updated on changes. This affects para_gui, which used to report the
+ old value until EOF.
-------------------------------
0.6.0 (2017-04-28) "fuzzy flux"
spx_afh_init, flac_afh_init, opus_afh_init;
/** The list of all status items */
-const char *status_item_list[] = {STATUS_ITEM_ARRAY};
+const char *status_item_list[] = {STATUS_ITEMS};
/**
* The list of supported audio formats.
"%s: %s\n" /* year */
"%s: %s\n" /* album */
"%s: %s\n", /* comment */
- status_item_list[SI_BITRATE], afhi->bitrate,
- status_item_list[SI_FORMAT], audio_format_name(audio_format_num),
- status_item_list[SI_FREQUENCY], afhi->frequency,
- status_item_list[SI_CHANNELS], afhi->channels,
- status_item_list[SI_SECONDS_TOTAL], afhi->seconds_total,
- status_item_list[SI_CHUNK_TIME], (long unsigned)afhi->chunk_tv.tv_sec,
+ status_item_list[SI_bitrate], afhi->bitrate,
+ status_item_list[SI_format], audio_format_name(audio_format_num),
+ status_item_list[SI_frequency], afhi->frequency,
+ status_item_list[SI_channels], afhi->channels,
+ status_item_list[SI_seconds_total], afhi->seconds_total,
+ status_item_list[SI_chunk_time], (long unsigned)afhi->chunk_tv.tv_sec,
(long unsigned)afhi->chunk_tv.tv_usec,
- status_item_list[SI_NUM_CHUNKS], afhi->chunks_total,
- status_item_list[SI_MAX_CHUNK_SIZE], afhi->max_chunk_size,
- status_item_list[SI_TECHINFO], afhi->techinfo? afhi->techinfo : "",
- status_item_list[SI_ARTIST], afhi->tags.artist? afhi->tags.artist : "",
- status_item_list[SI_TITLE], afhi->tags.title? afhi->tags.title : "",
- status_item_list[SI_YEAR], afhi->tags.year? afhi->tags.year : "",
- status_item_list[SI_ALBUM], afhi->tags.album? afhi->tags.album : "",
- status_item_list[SI_COMMENT], afhi->tags.comment? afhi->tags.comment : ""
+ status_item_list[SI_num_chunks], afhi->chunks_total,
+ status_item_list[SI_max_chunk_size], afhi->max_chunk_size,
+ status_item_list[SI_techinfo], afhi->techinfo? afhi->techinfo : "",
+ status_item_list[SI_artist], afhi->tags.artist? afhi->tags.artist : "",
+ status_item_list[SI_title], afhi->tags.title? afhi->tags.title : "",
+ status_item_list[SI_year], afhi->tags.year? afhi->tags.year : "",
+ status_item_list[SI_album], afhi->tags.album? afhi->tags.album : "",
+ status_item_list[SI_comment], afhi->tags.comment? afhi->tags.comment : ""
);
}
&pard->afh_context);
if (ret < 0)
goto out;
- PARA_INFO_LOG("adding %zu bytes\n", size);
+ PARA_DEBUG_LOG("adding %zu bytes\n", size);
btr_add_output_dont_free(start, size, btrn);
}
ret = -E_RECV_EOF;
ret = change_current_mood(arg + 2);
mode = PLAY_MODE_MOOD;
} else
- return -E_AFS_SYNTAX;
+ return -ERRNO_TO_PARA_ERROR(EINVAL);
if (ret < 0)
return ret;
}
strncpy(mmd->afs_mode_string, arg,
sizeof(mmd->afs_mode_string));
mmd->afs_mode_string[sizeof(mmd->afs_mode_string) - 1] = '\0';
+ mmd->events++;
mutex_unlock(mmd_mutex);
} else {
mutex_lock(mmd_mutex);
strcpy(mmd->afs_mode_string, "dummy");
+ mmd->events++;
mutex_unlock(mmd_mutex);
current_mop = NULL;
}
goto out;
/* ignore subsequent errors (but log them) */
para_printf(&aca->pbout, "could not activate %s\n", arg);
- if (current_mop) {
+ if (current_mop && strcmp(current_mop, arg) != 0) {
int ret2;
para_printf(&aca->pbout, "switching back to %s\n", current_mop);
ret2 = activate_mood_or_playlist(current_mop, &num_admissible);
static void init_admissible_files(const char *arg)
{
- if (activate_mood_or_playlist(arg, NULL) < 0)
+ int ret = activate_mood_or_playlist(arg, NULL);
+ if (ret < 0) {
+ assert(arg);
+ PARA_WARNING_LOG("could not activate %s: %s\n", arg,
+ para_strerror(-ret));
activate_mood_or_playlist(NULL, NULL); /* always successful */
+ }
}
static int setup_command_socket_or_die(void)
struct osl_object path_obj;
int ret = osl(osl_get_object(audio_file_table, row, AFTCOL_PATH,
&path_obj));
+
if (ret < 0)
- return ret;
- *path = path_obj.data;
- return 1;
+ *path = NULL;
+ else
+ *path = path_obj.data;
+ return ret;
}
/**
char *att_text;
int ret;
- WRITE_STATUS_ITEM(b, SI_ATTRIBUTES_BITMAP, "%s\n", att_bitmap);
+ WRITE_STATUS_ITEM(b, SI_attributes_bitmap, "%s\n", att_bitmap);
ret = get_attribute_text(&afsi->attributes, " ", &att_text);
if (ret < 0)
return ret;
- WRITE_STATUS_ITEM(b, SI_ATTRIBUTES_TXT, "%s\n", att_text);
+ WRITE_STATUS_ITEM(b, SI_attributes_txt, "%s\n", att_text);
free(att_text);
return ret;
}
{
char *lyrics_name;
- WRITE_STATUS_ITEM(b, SI_LYRICS_ID, "%u\n", afsi->lyrics_id);
+ WRITE_STATUS_ITEM(b, SI_lyrics_id, "%u\n", afsi->lyrics_id);
lyr_get_name_by_id(afsi->lyrics_id, &lyrics_name);
- WRITE_STATUS_ITEM(b, SI_LYRICS_NAME, "%s\n", lyrics_name?
+ WRITE_STATUS_ITEM(b, SI_lyrics_name, "%s\n", lyrics_name?
lyrics_name : "(none)");
}
{
char *image_name;
- WRITE_STATUS_ITEM(b, SI_IMAGE_ID, "%u\n", afsi->image_id);
+ WRITE_STATUS_ITEM(b, SI_image_id, "%u\n", afsi->image_id);
img_get_name_by_id(afsi->image_id, &image_name);
- WRITE_STATUS_ITEM(b, SI_IMAGE_NAME, "%s\n", image_name?
+ WRITE_STATUS_ITEM(b, SI_image_name, "%s\n", image_name?
image_name : "(none)");
}
char *val;
if (basename) {
- WRITE_STATUS_ITEM(b, SI_BASENAME, "%s\n", path);
+ WRITE_STATUS_ITEM(b, SI_basename, "%s\n", path);
return;
}
- WRITE_STATUS_ITEM(b, SI_PATH, "%s\n", path);
+ WRITE_STATUS_ITEM(b, SI_path, "%s\n", path);
val = para_basename(path);
- WRITE_STATUS_ITEM(b, SI_BASENAME, "%s\n", val? val : "");
+ WRITE_STATUS_ITEM(b, SI_basename, "%s\n", val? val : "");
val = para_dirname(path);
- WRITE_STATUS_ITEM(b, SI_DIRECTORY, "%s\n", val? val : "");
+ WRITE_STATUS_ITEM(b, SI_directory, "%s\n", val? val : "");
free(val);
}
}
write_filename_items(b, d->path, lls_opt_given(r_b));
if (lls_opt_given(r_a))
- WRITE_STATUS_ITEM(b, SI_SCORE, "%li\n", d->score);
+ WRITE_STATUS_ITEM(b, SI_score, "%li\n", d->score);
ret = write_attribute_items(b, att_buf, afsi);
if (ret < 0)
goto out;
write_image_items(b, afsi);
write_lyrics_items(b, afsi);
hash_to_asc(d->hash, asc_hash);
- WRITE_STATUS_ITEM(b, SI_HASH, "%s\n", asc_hash);
- WRITE_STATUS_ITEM(b, SI_BITRATE, "%dkbit/s\n", afhi->bitrate);
- WRITE_STATUS_ITEM(b, SI_FORMAT, "%s\n",
+ WRITE_STATUS_ITEM(b, SI_hash, "%s\n", asc_hash);
+ WRITE_STATUS_ITEM(b, SI_bitrate, "%dkbit/s\n", afhi->bitrate);
+ WRITE_STATUS_ITEM(b, SI_format, "%s\n",
audio_format_name(afsi->audio_format_id));
- WRITE_STATUS_ITEM(b, SI_FREQUENCY, "%dHz\n", afhi->frequency);
- WRITE_STATUS_ITEM(b, SI_CHANNELS, "%d\n", afhi->channels);
- WRITE_STATUS_ITEM(b, SI_DURATION, "%s\n", duration_buf);
- WRITE_STATUS_ITEM(b, SI_SECONDS_TOTAL, "%" PRIu32 "\n",
+ WRITE_STATUS_ITEM(b, SI_frequency, "%dHz\n", afhi->frequency);
+ WRITE_STATUS_ITEM(b, SI_channels, "%d\n", afhi->channels);
+ WRITE_STATUS_ITEM(b, SI_duration, "%s\n", duration_buf);
+ WRITE_STATUS_ITEM(b, SI_seconds_total, "%" PRIu32 "\n",
afhi->seconds_total);
- WRITE_STATUS_ITEM(b, SI_LAST_PLAYED, "%s\n", last_played_time);
- WRITE_STATUS_ITEM(b, SI_NUM_PLAYED, "%u\n", afsi->num_played);
- WRITE_STATUS_ITEM(b, SI_AMPLIFICATION, "%u\n", afsi->amp);
- WRITE_STATUS_ITEM(b, SI_CHUNK_TIME, "%lu\n", tv2ms(&afhi->chunk_tv));
- WRITE_STATUS_ITEM(b, SI_NUM_CHUNKS, "%" PRIu32 "\n",
+ WRITE_STATUS_ITEM(b, SI_last_played, "%s\n", last_played_time);
+ WRITE_STATUS_ITEM(b, SI_num_played, "%u\n", afsi->num_played);
+ WRITE_STATUS_ITEM(b, SI_amplification, "%u\n", afsi->amp);
+ WRITE_STATUS_ITEM(b, SI_chunk_time, "%lu\n", tv2ms(&afhi->chunk_tv));
+ WRITE_STATUS_ITEM(b, SI_num_chunks, "%" PRIu32 "\n",
afhi->chunks_total);
- WRITE_STATUS_ITEM(b, SI_MAX_CHUNK_SIZE, "%" PRIu32 "\n",
+ WRITE_STATUS_ITEM(b, SI_max_chunk_size, "%" PRIu32 "\n",
afhi->max_chunk_size);
- WRITE_STATUS_ITEM(b, SI_TECHINFO, "%s\n", afhi->techinfo);
- WRITE_STATUS_ITEM(b, SI_ARTIST, "%s\n", afhi->tags.artist);
- WRITE_STATUS_ITEM(b, SI_TITLE, "%s\n", afhi->tags.title);
- WRITE_STATUS_ITEM(b, SI_YEAR, "%s\n", afhi->tags.year);
- WRITE_STATUS_ITEM(b, SI_ALBUM, "%s\n", afhi->tags.album);
- WRITE_STATUS_ITEM(b, SI_COMMENT, "%s\n", afhi->tags.comment);
+ WRITE_STATUS_ITEM(b, SI_techinfo, "%s\n", afhi->techinfo);
+ WRITE_STATUS_ITEM(b, SI_artist, "%s\n", afhi->tags.artist);
+ WRITE_STATUS_ITEM(b, SI_title, "%s\n", afhi->tags.title);
+ WRITE_STATUS_ITEM(b, SI_year, "%s\n", afhi->tags.year);
+ WRITE_STATUS_ITEM(b, SI_album, "%s\n", afhi->tags.album);
+ WRITE_STATUS_ITEM(b, SI_comment, "%s\n", afhi->tags.comment);
if (opts->mode == LS_MODE_MBOX) {
struct osl_object lyrics_def;
lyr_get_def_by_id(afsi->lyrics_id, &lyrics_def);
ret = strftime(mtime_str, 29, "%b %d %Y", &mtime_tm);
assert(ret > 0); /* number of bytes placed in mtime_str */
out:
- WRITE_STATUS_ITEM(pb, SI_MTIME, "%s\n", mtime_str);
- WRITE_STATUS_ITEM(pb, SI_FILE_SIZE, "%ld\n", statbuf.st_size / 1024);
+ WRITE_STATUS_ITEM(pb, SI_mtime, "%s\n", mtime_str);
+ WRITE_STATUS_ITEM(pb, SI_file_size, "%ld\n", statbuf.st_size / 1024);
}
static int make_status_items(void)
time_t current_time;
int ret;
+ if (!status_item_ls_data.path) /* no audio file open */
+ return 0;
ret = lls_parse(ARRAY_SIZE(argv), argv, cmd, &opts.lpr, NULL);
assert(ret >= 0);
time(¤t_time);
return ret;
make_status_items();
return 1;
+ }
+ case BLOB_RENAME:
+ case BLOB_REMOVE:
+ case BLOB_ADD: {
+ /*
+ * These events are rare. We don't bother to check whether the
+ * current status items are affected and simply recreate them
+ * every time.
+ */
+ make_status_items();
} default:
return 0;
}
fn->private_data = pad;
fn->min_iqs = 2;
- if (!given && stat_item_values[SI_AMPLIFICATION])
- sscanf(stat_item_values[SI_AMPLIFICATION], "%u", &pad->amp);
+ if (!given && stat_item_values[SI_amplification])
+ sscanf(stat_item_values[SI_amplification], "%u", &pad->amp);
else
pad->amp = amp_arg;
PARA_INFO_LOG("amplification: %u (scaling factor: %1.2f)\n",
static void stat_completer(struct i9e_completion_info *ci,
struct i9e_completion_result *cr)
{
- char *sia[] = {STATUS_ITEM_ARRAY NULL};
+ char *sia[] = {STATUS_ITEMS NULL};
char *opts[] = {LSG_AUDIOD_CMD_STAT_OPTS, NULL};
if (ci->word_num <= 2 && ci->word && ci->word[0] == '-')
EMBRACE(.name = name, .context = rn));
ret = r->open(rn);
if (ret < 0) {
+ PARA_ERROR_LOG("could not open %s receiver\n", name);
btr_remove_node(&rn->btrn);
free(rn);
return ret;
{
long unsigned sec, usec;
- if (stat_task->clock_diff_count && itemnum != SI_CURRENT_TIME)
+ if (stat_task->clock_diff_count && itemnum != SI_current_time)
return 1;
free(stat_item_values[itemnum]);
stat_item_values[itemnum] = para_strdup(buf);
stat_client_write_item(itemnum);
switch (itemnum) {
- case SI_STATUS_FLAGS:
+ case SI_status_flags:
stat_task->vss_status = 0;
if (strchr(buf, 'N'))
stat_task->vss_status |= VSS_STATUS_FLAG_NEXT;
if (strchr(buf, 'P'))
stat_task->vss_status |= VSS_STATUS_FLAG_PLAYING;
break;
- case SI_OFFSET:
+ case SI_offset:
stat_task->offset_seconds = atoi(buf);
break;
- case SI_SECONDS_TOTAL:
+ case SI_seconds_total:
stat_task->length_seconds = atoi(buf);
break;
- case SI_STREAM_START:
+ case SI_stream_start:
if (sscanf(buf, "%lu.%lu", &sec, &usec) == 2) {
stat_task->server_stream_start.tv_sec = sec;
stat_task->server_stream_start.tv_usec = usec;
}
break;
- case SI_CURRENT_TIME:
+ case SI_current_time:
if (sscanf(buf, "%lu.%lu", &sec, &usec) == 2) {
struct timeval tv = {sec, usec};
compute_time_diff(&tv);
}
break;
- case SI_FORMAT:
+ case SI_format:
stat_task->current_audio_format_num
= get_audio_format_num(buf);
}
client_open(argc, argv, &st->ct, NULL, NULL, st->btrn, s);
set_stat_task_restart_barrier(5);
}
- free(stat_item_values[SI_BASENAME]);
- stat_item_values[SI_BASENAME] = para_strdup(
+ free(stat_item_values[SI_basename]);
+ stat_item_values[SI_basename] = para_strdup(
"no connection to para_server");
- stat_client_write_item(SI_BASENAME);
+ stat_client_write_item(SI_basename);
st->last_status_read = *now;
out:
start_stop_decoders();
static int num_clients;
/** The list of all status items used by para_{server,audiod,gui}. */
-const char *status_item_list[] = {STATUS_ITEM_ARRAY};
+const char *status_item_list[] = {STATUS_ITEMS};
static void dump_stat_client_list(void)
{
{
char *old, *new;
- old = stat_item_values[SI_PLAY_TIME];
+ old = stat_item_values[SI_play_time];
new = get_time_string();
if (new) {
if (force || !old || strcmp(old, new)) {
free(old);
- stat_item_values[SI_PLAY_TIME] = new;
- stat_client_write_item(SI_PLAY_TIME);
+ stat_item_values[SI_play_time] = new;
+ stat_client_write_item(SI_play_time);
} else
free(new);
}
new = daemon_get_uptime_str(now);
- old = stat_item_values[SI_AUDIOD_UPTIME];
+ old = stat_item_values[SI_audiod_uptime];
if (force || !old || strcmp(old, new)) {
free(old);
- stat_item_values[SI_AUDIOD_UPTIME] = new;
- stat_client_write_item(SI_AUDIOD_UPTIME);
+ stat_item_values[SI_audiod_uptime] = new;
+ stat_client_write_item(SI_audiod_uptime);
} else
free(new);
- old = stat_item_values[SI_AUDIOD_STATUS];
+ old = stat_item_values[SI_audiod_status];
new = audiod_status_string();
if (force || !old || strcmp(old, new)) {
free(old);
- stat_item_values[SI_AUDIOD_STATUS] = new;
- stat_client_write_item(SI_AUDIOD_STATUS);
+ stat_item_values[SI_audiod_status] = new;
+ stat_client_write_item(SI_audiod_status);
} else
free(new);
- old = stat_item_values[SI_DECODER_FLAGS];
+ old = stat_item_values[SI_decoder_flags];
new = audiod_get_decoder_flags();
if (force || !old || strcmp(old, new)) {
free(old);
- stat_item_values[SI_DECODER_FLAGS] = new;
- stat_client_write_item(SI_DECODER_FLAGS);
+ stat_item_values[SI_decoder_flags] = new;
+ stat_client_write_item(SI_decoder_flags);
} else
free(new);
}
./configure $@ > /dev/null
echo compiling...
make clean > /dev/null 2>&1
-make -j $n > /dev/null
+make -j $n > /dev/null && make check
if (vlc->table_size > vlc->table_allocated) {
vlc->table_allocated += (1 << vlc->bits);
vlc->table = para_realloc(vlc->table,
- sizeof(VLC_TYPE) * 2 * vlc->table_allocated);
+ sizeof(int16_t) * 2 * vlc->table_allocated);
}
}
{
int i, j, k, n, table_size, table_index, nb, n1, idx;
uint32_t code;
- VLC_TYPE(*table)[2];
+ int16_t (*table)[2];
table_size = 1 << table_nb_bits;
table_index = vlc->table_size;
* Parse a vlc code.
*
* \param gbc The getbit context structure.
- * \param table The vlc tables to use.
- * \param bits The number of bits which will be read at once.
- *
- * The \a bits parameter must be identical to the \a nb_bits value supplied to
- * \ref init_vlc().
+ * \param vlc The vlc tables to use.
*
* \return The vlc code.
*/
-int get_vlc(struct getbit_context *gbc, VLC_TYPE(*table)[2], int bits)
+int get_vlc(struct getbit_context *gbc, const struct vlc *vlc)
{
int n, idx, nb_bits, code;
- idx = show_bits(gbc, bits);
- code = table[idx][0];
- n = table[idx][1];
+ idx = show_bits(gbc, vlc->bits);
+ code = vlc->table[idx][0];
+ n = vlc->table[idx][1];
if (n < 0) {
- skip_bits(gbc, bits);
+ skip_bits(gbc, vlc->bits);
nb_bits = -n;
idx = show_bits(gbc, nb_bits) + code;
- code = table[idx][0];
- n = table[idx][1];
+ code = vlc->table[idx][0];
+ n = vlc->table[idx][1];
if (n < 0) {
skip_bits(gbc, nb_bits);
nb_bits = -n;
idx = show_bits(gbc, nb_bits) + code;
- code = table[idx][0];
- n = table[idx][1];
+ code = vlc->table[idx][0];
+ n = vlc->table[idx][1];
}
}
skip_bits(gbc, n);
struct getbit_context {
/** Start of the internal buffer. */
const uint8_t *buffer;
- /** End of the internal buffer. */
- const uint8_t *buffer_end;
+ /** Length of buffer in bits (always a multiple of 8). */
+ uint32_t num_bits;
/** Bit counter. */
int index;
};
-#define VLC_TYPE int16_t
-
/** A variable length code table. */
struct vlc {
/** Number of bits of the table. */
int bits;
/** The code and the bits table. */
- VLC_TYPE(*table)[2];
+ int16_t (*table)[2];
/** The size of the table. */
int table_size;
/** Amount of memory allocated so far. */
static inline uint32_t show_bits(struct getbit_context *gbc, int num)
{
int idx = gbc->index;
- const char *p = (const char *)gbc->buffer + (idx >> 3);
- uint32_t x = read_u32_be(p);
+ const char *p;
+ uint32_t x;
+
+ assert(idx + num <= gbc->num_bits);
+ p = (const char *)gbc->buffer + (idx >> 3);
+ x = read_u32_be(p);
return (x << (idx & 7)) >> (32 - num);
}
static inline void skip_bits(struct getbit_context *gbc, int n)
{
+ assert(gbc->index + n <= gbc->num_bits);
gbc->index += n;
}
static inline unsigned int get_bits(struct getbit_context *gbc, int n)
{
- unsigned int ret = show_bits(gbc, n);
+ unsigned int ret = show_bits(gbc, n); /* checks n */
skip_bits(gbc, n);
return ret;
}
/* This is rather hot, we can do better than get_bits(gbc, 1). */
static inline unsigned int get_bit(struct getbit_context *gbc)
{
- int idx = gbc->index++;
- uint8_t tmp = gbc->buffer[idx >> 3], mask = 1 << (7 - (idx & 7));
+ int idx;
+ uint8_t tmp, mask;
+
+ assert(gbc->index < gbc->num_bits);
+ idx = gbc->index++;
+ tmp = gbc->buffer[idx >> 3];
+ mask = 1 << (7 - (idx & 7));
return !!(tmp & mask);
}
const uint8_t *buffer, int size)
{
gbc->buffer = buffer;
- gbc->buffer_end = buffer + size;
+ gbc->num_bits = size * 8;
gbc->index = 0;
}
void init_vlc(struct vlc *vlc, int nb_bits, int nb_codes, const void *bits,
const void *codes, int codes_size);
void free_vlc(struct vlc *vlc);
-int get_vlc(struct getbit_context *gbc, VLC_TYPE(*table)[2], int bits);
+int get_vlc(struct getbit_context *gbc, const struct vlc *vlc);
*/
static int uint32_compare(const struct osl_object *obj1, const struct osl_object *obj2)
{
- uint32_t d1 = read_u32((const char *)obj1->data);
- uint32_t d2 = read_u32((const char *)obj2->data);
+ uint32_t d1 = read_u32(obj1->data);
+ uint32_t d2 = read_u32(obj2->data);
if (d1 < d2)
return 1;
* clang is not smart enough to prove this and complains nevertheless.
* Casting the return value to void silences clang.
*/
- (void)WRITE_STATUS_ITEM(&b, SI_STATUS, "%s\n", status);
- (void)WRITE_STATUS_ITEM(&b, SI_STATUS_FLAGS, "%s\n", flags);
- (void)WRITE_STATUS_ITEM(&b, SI_OFFSET, "%li\n", offset);
- (void)WRITE_STATUS_ITEM(&b, SI_AFS_MODE, "%s\n", mmd->afs_mode_string);
- (void)WRITE_STATUS_ITEM(&b, SI_STREAM_START, "%lu.%lu\n",
+ (void)WRITE_STATUS_ITEM(&b, SI_status, "%s\n", status);
+ (void)WRITE_STATUS_ITEM(&b, SI_status_flags, "%s\n", flags);
+ (void)WRITE_STATUS_ITEM(&b, SI_offset, "%li\n", offset);
+ (void)WRITE_STATUS_ITEM(&b, SI_afs_mode, "%s\n", mmd->afs_mode_string);
+ (void)WRITE_STATUS_ITEM(&b, SI_stream_start, "%lu.%lu\n",
(long unsigned)nmmd->stream_start.tv_sec,
(long unsigned)nmmd->stream_start.tv_usec);
- (void)WRITE_STATUS_ITEM(&b, SI_CURRENT_TIME, "%lu.%lu\n",
+ (void)WRITE_STATUS_ITEM(&b, SI_current_time, "%lu.%lu\n",
(long unsigned)current_time.tv_sec,
(long unsigned)current_time.tv_usec);
free(flags);
struct lls_parse_result *lpr, struct sender_command_data *scd)
{
int i, ret;
- const char *subcmds[] = {SENDER_SUBCOMMANDS};
+ const char * const subcmds[] = {SENDER_SUBCOMMANDS};
const char *arg;
char *errctx;
unsigned num_inputs = lls_num_inputs(lpr);
return -E_COMMAND_SYNTAX;
scd->sender_num = i;
arg = lls_input(1, lpr);
- for (i = 0; subcmds[i]; i++)
+ for (i = 0; i < NUM_SENDER_CMDS; i++)
if (!strcmp(subcmds[i], arg))
break;
- if (!subcmds[i])
+ if (i == NUM_SENDER_CMDS)
return -E_COMMAND_SYNTAX;
scd->cmd_num = i;
if (!senders[scd->sender_num].client_cmds[scd->cmd_num])
/** These status items are cleared if no audio file is currently open. */
#define EMPTY_STATUS_ITEMS \
- ITEM(PATH) \
- ITEM(DIRECTORY) \
- ITEM(BASENAME) \
- ITEM(SCORE) \
- ITEM(ATTRIBUTES_BITMAP) \
- ITEM(ATTRIBUTES_TXT) \
- ITEM(HASH) \
- ITEM(IMAGE_ID) \
- ITEM(IMAGE_NAME) \
- ITEM(LYRICS_ID) \
- ITEM(LYRICS_NAME) \
- ITEM(BITRATE) \
- ITEM(FORMAT) \
- ITEM(FREQUENCY) \
- ITEM(CHANNELS) \
- ITEM(DURATION) \
- ITEM(SECONDS_TOTAL) \
- ITEM(NUM_PLAYED) \
- ITEM(LAST_PLAYED) \
- ITEM(TECHINFO) \
- ITEM(ARTIST) \
- ITEM(TITLE) \
- ITEM(YEAR) \
- ITEM(ALBUM) \
- ITEM(COMMENT) \
- ITEM(MTIME) \
- ITEM(FILE_SIZE) \
- ITEM(CHUNK_TIME) \
- ITEM(NUM_CHUNKS) \
- ITEM(AMPLIFICATION) \
+ ITEM(path) \
+ ITEM(directory) \
+ ITEM(basename) \
+ ITEM(score) \
+ ITEM(attributes_bitmap) \
+ ITEM(attributes_txt) \
+ ITEM(hash) \
+ ITEM(image_id) \
+ ITEM(image_name) \
+ ITEM(lyrics_id) \
+ ITEM(lyrics_name) \
+ ITEM(bitrate) \
+ ITEM(format) \
+ ITEM(frequency) \
+ ITEM(channels) \
+ ITEM(duration) \
+ ITEM(seconds_total) \
+ ITEM(num_played) \
+ ITEM(last_played) \
+ ITEM(techinfo) \
+ ITEM(artist) \
+ ITEM(title) \
+ ITEM(year) \
+ ITEM(album) \
+ ITEM(comment) \
+ ITEM(mtime) \
+ ITEM(file_size) \
+ ITEM(chunk_time) \
+ ITEM(num_chunks) \
+ ITEM(amplification) \
-/**
- * Write a list of audio-file related status items with empty values.
- *
- * This is used by vss when currently no audio file is open.
+/*
+ * Create a set of audio-file related status items with empty values. These are
+ * written to stat clients when no audio file is open.
*/
static unsigned empty_status_items(bool parser_friendly, char **result)
{
unsigned char challenge_hash[HASH_SIZE];
char *command = NULL, *buf = para_malloc(HANDSHAKE_BUFSIZE) /* must be on the heap */;
size_t numbytes;
- struct command_context cc_struct = {.peer = peername}, *cc = &cc_struct;
+ struct command_context cc_struct = {.u = NULL}, *cc = &cc_struct;
struct iovec iov;
struct connection_features cf;
/** Per connection data available to command handlers. */
struct command_context {
- /** Network address of the peer. */
- const char *peer;
/** The paraslash user that executes this command. */
struct user *u;
/** File descriptor and crypto keys. */
test -z "$M4" && AC_MSG_ERROR(
[The m4 macro processor is required to build this package])
-AC_PATH_PROG([lopsubgen], [lopsubgen])
-test -z "$lopsubgen" && AC_MSG_ERROR(
- [lopsubgen is required to build this package])
-
AC_PROG_CC
AC_PROG_CPP
LIB_SUBST_FLAGS(osl)
UNSTASH_FLAGS
######################################################################## lopsub
+HAVE_LOPSUB=yes
+AC_PATH_PROG([LOPSUBGEN], [lopsubgen])
+test -z "$LOPSUBGEN" && HAVE_LOPSUB=no
STASH_FLAGS
LIB_ARG_WITH([lopsub], [-llopsub])
-HAVE_LOPSUB=yes
AC_CHECK_HEADER(lopsub.h, [], [HAVE_LOPSUB=no])
AC_CHECK_LIB([lopsub], [lls_merge], [], [HAVE_LOPSUB=no])
if test $HAVE_LOPSUB = no; then AC_MSG_ERROR([
AC_MSG_RESULT($msg)
UNSTASH_FLAGS
########################################################################### ucred
-AC_MSG_CHECKING(for struct ucred)
-AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+AC_CHECK_TYPE([struct ucred], [
+ AC_DEFINE(HAVE_UCRED, 1, define to 1 you have struct ucred)
+], [], [
#include <sys/types.h>
#include <sys/socket.h>
-]], [[
- struct ucred sucred; sucred.pid=0;
-]])],[have_ucred=yes],[have_ucred=no])
-AC_MSG_RESULT($have_ucred)
-if test ${have_ucred} = yes; then
- AC_DEFINE(HAVE_UCRED, 1, define to 1 you have struct ucred)
-fi
+])
########################################################################### curses
STASH_FLAGS
LIB_ARG_WITH([curses], [])
LIB_SUBST_FLAGS(curses)
UNSTASH_FLAGS
########################################################################### ip_mreqn
-AC_MSG_CHECKING(for struct ip_mreqn (UDPv4 multicast))
-AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+AC_CHECK_TYPE([struct ip_mreqn], [
+ AC_DEFINE(HAVE_IP_MREQN, 1, define to 1 if you have struct ip_mreqn)
+], [], [
#include <netdb.h>
#include <net/if.h>
-]], [[
- struct ip_mreqn mn;
- mn.imr_ifindex = 0;
-]])],[have_ip_mreqn=yes],[have_ip_mreqn=no])
-AC_MSG_RESULT($have_ip_mreqn)
-if test ${have_ip_mreqn} = yes; then
- AC_DEFINE(HAVE_IP_MREQN, 1, define to 1 if you have struct ip_mreqn)
-fi
+])
########################################################################### ogg
STASH_FLAGS
LIB_ARG_WITH([ogg], [-logg])
fi
audioc_objs="$audioc_errlist_objs"
AC_SUBST(audioc_objs, add_dot_o($audioc_objs))
-################################################################## status items
-
-status_items="basename status num_played mtime bitrate frequency file_size
-status_flags format score techinfo afs_mode
-attributes_txt decoder_flags audiod_status play_time attributes_bitmap
-offset seconds_total stream_start current_time audiod_uptime image_id
-lyrics_id duration directory lyrics_name image_name path hash channels
-last_played num_chunks chunk_time amplification artist title year album
-comment max_chunk_size"
-
-result=
-for i in $status_items; do
- result="$result SI_$(echo $i | tr 'a-z' 'A-Z'), "
-done
-AC_DEFINE_UNQUOTED(STATUS_ITEM_ENUM, [$result],
- [enum of all status items])
-
-result=
-for i in $status_items; do
- result="$result \"$i\", "
-done
-AC_DEFINE_UNQUOTED(STATUS_ITEM_ARRAY, [$result],
- [char * array of all status items])
AC_DEFINE_UNQUOTED(AUDIO_FORMAT_HANDLERS, "$audio_format_handlers",
[formats supported by para_server and para_afh])
-
AC_SUBST(executables)
AC_OUTPUT
#include "fd.h"
#include "crypt_backend.h"
#include "base64.h"
+#include "portable_io.h"
struct asymmetric_key {
RSA *rsa;
return -E_BIGNUM;
if (p + 4 > end)
return -E_BIGNUM;
- bnsize = read_ssh_u32(p);
+ bnsize = read_u32_be(p);
PARA_DEBUG_LOG("bnsize: %u\n", bnsize);
p += 4;
if (p + bnsize < p)
#define AES_CRT128_BLOCK_SIZE 16
size_t is_ssh_rsa_key(char *data, size_t size);
-uint32_t read_ssh_u32(const void *vp);
int check_ssh_key_header(const unsigned char *blob, int blen);
int check_private_key_file(const char *file);
#include "string.h"
#include "crypt.h"
#include "crypt_backend.h"
+#include "portable_io.h"
/** If the key begins with this text, we treat it as an ssh key. */
#define KEY_TYPE_TXT "ssh-rsa"
return cp - data;
}
-/**
- * Read a 4-byte number from a buffer in big-endian format.
- *
- * \param vp The buffer.
- *
- * The byte-order of the buffer is expected to be big-endian, unlike read_u32()
- * of portable_io.h which expects little endian.
- *
- * \return The 32 bit number given by \a vp.
- */
-uint32_t read_ssh_u32(const void *vp)
-{
- const unsigned char *p = (const unsigned char *)vp;
- uint32_t v;
-
- v = (uint32_t)p[0] << 24;
- v |= (uint32_t)p[1] << 16;
- v |= (uint32_t)p[2] << 8;
- v |= (uint32_t)p[3];
-
- return v;
-}
-
/**
* Sanity checks for the header of an ssh key.
*
if (p + 4 > end)
return -E_SSH_KEY_HEADER;
- rlen = read_ssh_u32(p);
+ rlen = read_u32_be(p);
p += 4;
if (p + rlen < p)
return -E_SSH_KEY_HEADER;
PARA_ERROR(AFS_SHORT_READ, "short read from afs socket"), \
PARA_ERROR(AFS_SIGNAL, "afs caught deadly signal"), \
PARA_ERROR(AFS_SOCKET, "afs socket not writable"), \
- PARA_ERROR(AFS_SYNTAX, "afs syntax error"), \
PARA_ERROR(AFT_SYNTAX, "audio file table syntax error"), \
PARA_ERROR(ALSA, "alsa error"), \
PARA_ERROR(ALSA_MIX_GET_VAL, "could not read control element state"), \
return ret;
}
-/**
- * A wrapper for fchdir().
- *
- * \param fd An open file descriptor.
- *
- * \return Standard.
- */
-static int para_fchdir(int fd)
-{
- if (fchdir(fd) < 0)
- return -ERRNO_TO_PARA_ERROR(errno);
- return 1;
-}
-
/**
* A wrapper for mkdir(2).
*
{
DIR *dir;
struct dirent *entry;
- int cwd_fd, ret2, ret = para_opendir(dirname, &dir, &cwd_fd);
+ int cwd_fd, ret = para_opendir(dirname, &dir, &cwd_fd);
if (ret < 0)
return ret == -ERRNO_TO_PARA_ERROR(EACCES)? 1 : ret;
ret = 1;
out:
closedir(dir);
- ret2 = para_fchdir(cwd_fd);
- if (ret2 < 0 && ret >= 0)
- ret = ret2;
+ if (fchdir(cwd_fd) < 0 && ret >= 0)
+ ret = -ERRNO_TO_PARA_ERROR(errno);
close(cwd_fd);
return ret;
}
#define OPT_UINT32_VAL(_name) (lls_uint32_val(0, OPT_RESULT(_name)))
/** The list of all status items used by para_{server,audiod,gui}. */
-const char *status_item_list[] = {STATUS_ITEM_ARRAY};
+const char *status_item_list[] = {STATUS_ITEMS};
/**
* Dummy version which only contains NULL pointers.
#include "string.h"
/** Iterate over all filters. */
-#define FOR_EACH_FILTER(j) for (j = 1; lls_cmd(j, filter_cmd_suite); j++)
+#define FOR_EACH_FILTER(j) for (j = 1; FILTER_CMD(j); j++)
/**
* Obtain a reference to a filter structure.
if (buf && buf[0])
goto dup;
switch (item_num) {
- case SI_ARTIST:
+ case SI_artist:
*c = para_strdup("(artist tag not set)");
goto print;
- case SI_TITLE:
+ case SI_title:
*c = para_strdup("(title tag not set)");
goto print;
- case SI_YEAR:
+ case SI_year:
*c = para_strdup("????");
goto print;
- case SI_ALBUM:
+ case SI_album:
*c = para_strdup("(album tag not set)");
goto print;
- case SI_COMMENT:
+ case SI_comment:
*c = para_strdup("(comment tag not set)");
goto print;
}
close(st->fd);
st->fd = -1;
clear_all_items();
- free(stat_content[SI_BASENAME]);
- stat_content[SI_BASENAME] =
+ free(stat_content[SI_basename]);
+ stat_content[SI_basename] =
para_strdup("stat command terminated!?");
print_all_items();
return 0;
t->dflt.bg = COLOR_BLUE;
t->sep_char = '*';
- d[SI_BASENAME].prefix = "";
- d[SI_BASENAME].postfix = "";
- d[SI_BASENAME].color.fg = COLOR_WHITE;
- d[SI_BASENAME].color.bg = COLOR_BLUE;
- d[SI_BASENAME].align = CENTER;
- d[SI_BASENAME].x = 0;
- d[SI_BASENAME].y = 7;
- d[SI_BASENAME].len = 100;
-
- d[SI_STATUS].prefix = "para_server: ";
- d[SI_STATUS].postfix = "";
- d[SI_STATUS].color.fg = COLOR_WHITE;
- d[SI_STATUS].color.bg = COLOR_BLUE;
- d[SI_STATUS].align = CENTER;
- d[SI_STATUS].x = 0;
- d[SI_STATUS].y = 60;
- d[SI_STATUS].len = 50;
-
- d[SI_AUDIOD_STATUS].prefix = "para_audiod: ";
- d[SI_AUDIOD_STATUS].postfix = "";
- d[SI_AUDIOD_STATUS].color.fg = COLOR_WHITE;
- d[SI_AUDIOD_STATUS].color.bg = COLOR_BLUE;
- d[SI_AUDIOD_STATUS].align = CENTER;
- d[SI_AUDIOD_STATUS].x = 50;
- d[SI_AUDIOD_STATUS].y = 60;
- d[SI_AUDIOD_STATUS].len = 50;
+ d[SI_basename].prefix = "";
+ d[SI_basename].postfix = "";
+ d[SI_basename].color.fg = COLOR_WHITE;
+ d[SI_basename].color.bg = COLOR_BLUE;
+ d[SI_basename].align = CENTER;
+ d[SI_basename].x = 0;
+ d[SI_basename].y = 7;
+ d[SI_basename].len = 100;
+
+ d[SI_status].prefix = "para_server: ";
+ d[SI_status].postfix = "";
+ d[SI_status].color.fg = COLOR_WHITE;
+ d[SI_status].color.bg = COLOR_BLUE;
+ d[SI_status].align = CENTER;
+ d[SI_status].x = 0;
+ d[SI_status].y = 60;
+ d[SI_status].len = 50;
+
+ d[SI_audiod_status].prefix = "para_audiod: ";
+ d[SI_audiod_status].postfix = "";
+ d[SI_audiod_status].color.fg = COLOR_WHITE;
+ d[SI_audiod_status].color.bg = COLOR_BLUE;
+ d[SI_audiod_status].align = CENTER;
+ d[SI_audiod_status].x = 50;
+ d[SI_audiod_status].y = 60;
+ d[SI_audiod_status].len = 50;
}
t->dflt.fg = COLOR_MAGENTA;
- d[SI_PLAY_TIME].prefix = "";
- d[SI_PLAY_TIME].postfix = "";
- d[SI_PLAY_TIME].color.fg = COLOR_CYAN;
- d[SI_PLAY_TIME].color.bg = COLOR_BLACK;
- d[SI_PLAY_TIME].align = CENTER;
- d[SI_PLAY_TIME].x = 0;
- d[SI_PLAY_TIME].y = 7;
- d[SI_PLAY_TIME].len = 35;
-
- d[SI_BASENAME].prefix = "";
- d[SI_BASENAME].postfix = "";
- d[SI_BASENAME].color.fg = COLOR_CYAN;
- d[SI_BASENAME].color.bg = COLOR_BLACK;
- d[SI_BASENAME].align = LEFT;
- d[SI_BASENAME].x = 35;
- d[SI_BASENAME].y = 7;
- d[SI_BASENAME].len = 65;
-
- d[SI_STATUS].prefix = "";
- d[SI_STATUS].postfix = " ";
- d[SI_STATUS].color.fg = COLOR_RED;
- d[SI_STATUS].color.bg = COLOR_BLACK;
- d[SI_STATUS].align = RIGHT;
- d[SI_STATUS].x = 0;
- d[SI_STATUS].y = 17;
- d[SI_STATUS].len = 11;
-
- d[SI_STATUS_FLAGS].prefix = "(";
- d[SI_STATUS_FLAGS].postfix = ")";
- d[SI_STATUS_FLAGS].color.fg = COLOR_RED;
- d[SI_STATUS_FLAGS].color.bg = COLOR_BLACK;
- d[SI_STATUS_FLAGS].align = LEFT;
- d[SI_STATUS_FLAGS].x = 11;
- d[SI_STATUS_FLAGS].y = 17;
- d[SI_STATUS_FLAGS].len = 10;
-
- d[SI_IMAGE_ID].prefix = "img: ";
- d[SI_IMAGE_ID].postfix = "";
- d[SI_IMAGE_ID].color.fg = COLOR_RED;
- d[SI_IMAGE_ID].color.bg = COLOR_BLACK;
- d[SI_IMAGE_ID].align = CENTER;
- d[SI_IMAGE_ID].x = 21;
- d[SI_IMAGE_ID].y = 17;
- d[SI_IMAGE_ID].len = 10;
-
- d[SI_LYRICS_ID].prefix = "lyr: ";
- d[SI_LYRICS_ID].postfix = "";
- d[SI_LYRICS_ID].color.fg = COLOR_RED;
- d[SI_LYRICS_ID].color.bg = COLOR_BLACK;
- d[SI_LYRICS_ID].align = CENTER;
- d[SI_LYRICS_ID].x = 31;
- d[SI_LYRICS_ID].y = 17;
- d[SI_LYRICS_ID].len = 11;
-
- d[SI_FORMAT].prefix = "format: ";
- d[SI_FORMAT].postfix = "";
- d[SI_FORMAT].color.fg = COLOR_RED;
- d[SI_FORMAT].color.bg = COLOR_BLACK;
- d[SI_FORMAT].align = CENTER;
- d[SI_FORMAT].x = 42;
- d[SI_FORMAT].y = 17;
- d[SI_FORMAT].len = 18;
-
- d[SI_NUM_PLAYED].prefix = "#";
- d[SI_NUM_PLAYED].postfix = "";
- d[SI_NUM_PLAYED].color.fg = COLOR_RED;
- d[SI_NUM_PLAYED].color.bg = COLOR_BLACK;
- d[SI_NUM_PLAYED].align = LEFT;
- d[SI_NUM_PLAYED].x = 60;
- d[SI_NUM_PLAYED].y = 17;
- d[SI_NUM_PLAYED].len = 5;
-
- d[SI_BITRATE].prefix = "";
- d[SI_BITRATE].postfix = "";
- d[SI_BITRATE].color.fg = COLOR_RED;
- d[SI_BITRATE].color.bg = COLOR_BLACK;
- d[SI_BITRATE].align = CENTER;
- d[SI_BITRATE].x = 65;
- d[SI_BITRATE].y = 17;
- d[SI_BITRATE].len = 13;
-
- d[SI_FREQUENCY].prefix = "";
- d[SI_FREQUENCY].postfix = "";
- d[SI_FREQUENCY].color.fg = COLOR_RED;
- d[SI_FREQUENCY].color.bg = COLOR_BLACK;
- d[SI_FREQUENCY].align = CENTER;
- d[SI_FREQUENCY].x = 78;
- d[SI_FREQUENCY].y = 17;
- d[SI_FREQUENCY].len = 10;
-
- d[SI_SCORE].prefix = "sc: ";
- d[SI_SCORE].postfix = "";
- d[SI_SCORE].color.fg = COLOR_RED;
- d[SI_SCORE].color.bg = COLOR_BLACK;
- d[SI_SCORE].align = CENTER;
- d[SI_SCORE].x = 88;
- d[SI_SCORE].y = 17;
- d[SI_SCORE].len = 10;
-
- d[SI_AUDIOD_STATUS].prefix = "";
- d[SI_AUDIOD_STATUS].postfix = "";
- d[SI_AUDIOD_STATUS].color.fg = COLOR_MAGENTA;
- d[SI_AUDIOD_STATUS].color.bg = COLOR_BLACK;
- d[SI_AUDIOD_STATUS].align = CENTER;
- d[SI_AUDIOD_STATUS].x = 0;
- d[SI_AUDIOD_STATUS].y = 27;
- d[SI_AUDIOD_STATUS].len = 5;
-
- d[SI_DECODER_FLAGS].prefix = "[";
- d[SI_DECODER_FLAGS].postfix = "]";
- d[SI_DECODER_FLAGS].color.fg = COLOR_MAGENTA;
- d[SI_DECODER_FLAGS].color.bg = COLOR_BLACK;
- d[SI_DECODER_FLAGS].align = CENTER;
- d[SI_DECODER_FLAGS].x = 5;
- d[SI_DECODER_FLAGS].y = 27;
- d[SI_DECODER_FLAGS].len = 10;
-
- d[SI_MTIME].prefix = "mod: ";
- d[SI_MTIME].postfix = "";
- d[SI_MTIME].color.fg = COLOR_MAGENTA;
- d[SI_MTIME].color.bg = COLOR_BLACK;
- d[SI_MTIME].align = CENTER;
- d[SI_MTIME].x = 15;
- d[SI_MTIME].y = 27;
- d[SI_MTIME].len = 22;
-
- d[SI_FILE_SIZE].prefix = "";
- d[SI_FILE_SIZE].postfix = "kb";
- d[SI_FILE_SIZE].color.fg = COLOR_MAGENTA;
- d[SI_FILE_SIZE].color.bg = COLOR_BLACK;
- d[SI_FILE_SIZE].align = CENTER;
- d[SI_FILE_SIZE].x = 37;
- d[SI_FILE_SIZE].y = 27;
- d[SI_FILE_SIZE].len = 10;
-
- d[SI_CHANNELS].prefix = "";
- d[SI_CHANNELS].postfix = "ch";
- d[SI_CHANNELS].color.fg = COLOR_MAGENTA;
- d[SI_CHANNELS].color.bg = COLOR_BLACK;
- d[SI_CHANNELS].align = CENTER;
- d[SI_CHANNELS].x = 47;
- d[SI_CHANNELS].y = 27;
- d[SI_CHANNELS].len = 5;
-
- d[SI_LAST_PLAYED].prefix = "lp: ";
- d[SI_LAST_PLAYED].postfix = "";
- d[SI_LAST_PLAYED].color.fg = COLOR_MAGENTA;
- d[SI_LAST_PLAYED].color.bg = COLOR_BLACK;
- d[SI_LAST_PLAYED].align = CENTER;
- d[SI_LAST_PLAYED].x = 52;
- d[SI_LAST_PLAYED].y = 27;
- d[SI_LAST_PLAYED].len = 21;
-
- d[SI_NUM_CHUNKS].prefix = "";
- d[SI_NUM_CHUNKS].postfix = "x";
- d[SI_NUM_CHUNKS].color.fg = COLOR_MAGENTA;
- d[SI_NUM_CHUNKS].color.bg = COLOR_BLACK;
- d[SI_NUM_CHUNKS].align = RIGHT;
- d[SI_NUM_CHUNKS].x = 73;
- d[SI_NUM_CHUNKS].y = 27;
- d[SI_NUM_CHUNKS].len = 11;
-
- d[SI_CHUNK_TIME].prefix = "";
- d[SI_CHUNK_TIME].postfix = "ms";
- d[SI_CHUNK_TIME].color.fg = COLOR_MAGENTA;
- d[SI_CHUNK_TIME].color.bg = COLOR_BLACK;
- d[SI_CHUNK_TIME].align = LEFT;
- d[SI_CHUNK_TIME].x = 84;
- d[SI_CHUNK_TIME].y = 27;
- d[SI_CHUNK_TIME].len = 8;
-
- d[SI_AMPLIFICATION].prefix = "amp:";
- d[SI_AMPLIFICATION].postfix = "";
- d[SI_AMPLIFICATION].color.fg = COLOR_MAGENTA;
- d[SI_AMPLIFICATION].color.bg = COLOR_BLACK;
- d[SI_AMPLIFICATION].align = RIGHT;
- d[SI_AMPLIFICATION].x = 92;
- d[SI_AMPLIFICATION].y = 27;
- d[SI_AMPLIFICATION].len = 8;
-
- d[SI_TECHINFO].prefix = "";
- d[SI_TECHINFO].postfix = "";
- d[SI_TECHINFO].color.fg = COLOR_GREEN;
- d[SI_TECHINFO].color.bg = COLOR_BLACK;
- d[SI_TECHINFO].align = CENTER;
- d[SI_TECHINFO].x = 0;
- d[SI_TECHINFO].y = 43;
- d[SI_TECHINFO].len = 100;
-
- d[SI_TITLE].prefix = "";
- d[SI_TITLE].postfix = ",";
- d[SI_TITLE].color.fg = COLOR_GREEN;
- d[SI_TITLE].color.bg = COLOR_BLACK;
- d[SI_TITLE].align = RIGHT;
- d[SI_TITLE].x = 0;
- d[SI_TITLE].y = 53;
- d[SI_TITLE].len = 45;
-
- d[SI_ARTIST].prefix = " by ";
- d[SI_ARTIST].postfix = "";
- d[SI_ARTIST].color.fg = COLOR_GREEN;
- d[SI_ARTIST].color.bg = COLOR_BLACK;
- d[SI_ARTIST].align = LEFT;
- d[SI_ARTIST].x = 45;
- d[SI_ARTIST].y = 53;
- d[SI_ARTIST].len = 45;
-
- d[SI_YEAR].prefix = "(";
- d[SI_YEAR].postfix = ")";
- d[SI_YEAR].color.fg = COLOR_GREEN;
- d[SI_YEAR].color.bg = COLOR_BLACK;
- d[SI_YEAR].align = RIGHT;
- d[SI_YEAR].x = 90;
- d[SI_YEAR].y = 53;
- d[SI_YEAR].len = 10;
-
- d[SI_ALBUM].prefix = "A: ";
- d[SI_ALBUM].postfix = ",";
- d[SI_ALBUM].color.fg = COLOR_GREEN;
- d[SI_ALBUM].color.bg = COLOR_BLACK;
- d[SI_ALBUM].align = RIGHT;
- d[SI_ALBUM].x = 0;
- d[SI_ALBUM].y = 63;
- d[SI_ALBUM].len = 50;
-
- d[SI_COMMENT].prefix = " C: ";
- d[SI_COMMENT].postfix = "";
- d[SI_COMMENT].color.fg = COLOR_GREEN;
- d[SI_COMMENT].color.bg = COLOR_BLACK;
- d[SI_COMMENT].align = LEFT;
- d[SI_COMMENT].x = 50;
- d[SI_COMMENT].y = 63;
- d[SI_COMMENT].len = 50;
-
- d[SI_AFS_MODE].prefix = "";
- d[SI_AFS_MODE].postfix = "";
- d[SI_AFS_MODE].color.fg = COLOR_YELLOW;
- d[SI_AFS_MODE].color.bg = COLOR_BLACK;
- d[SI_AFS_MODE].align = CENTER;
- d[SI_AFS_MODE].x = 0;
- d[SI_AFS_MODE].y = 77;
- d[SI_AFS_MODE].len = 100;
-
- d[SI_ATTRIBUTES_TXT].prefix = "";
- d[SI_ATTRIBUTES_TXT].postfix = "";
- d[SI_ATTRIBUTES_TXT].color.fg = COLOR_YELLOW;
- d[SI_ATTRIBUTES_TXT].color.bg = COLOR_BLACK;
- d[SI_ATTRIBUTES_TXT].align = CENTER;
- d[SI_ATTRIBUTES_TXT].x = 0;
- d[SI_ATTRIBUTES_TXT].y = 87;
- d[SI_ATTRIBUTES_TXT].len = 100;
-
- d[SI_DIRECTORY].prefix = "dir: ";
- d[SI_DIRECTORY].postfix = "";
- d[SI_DIRECTORY].color.fg = COLOR_YELLOW;
- d[SI_DIRECTORY].color.bg = COLOR_BLACK;
- d[SI_DIRECTORY].align = CENTER;
- d[SI_DIRECTORY].x = 0;
- d[SI_DIRECTORY].y = 97;
- d[SI_DIRECTORY].len = 100;
+ d[SI_play_time].prefix = "";
+ d[SI_play_time].postfix = "";
+ d[SI_play_time].color.fg = COLOR_CYAN;
+ d[SI_play_time].color.bg = COLOR_BLACK;
+ d[SI_play_time].align = CENTER;
+ d[SI_play_time].x = 0;
+ d[SI_play_time].y = 7;
+ d[SI_play_time].len = 35;
+
+ d[SI_basename].prefix = "";
+ d[SI_basename].postfix = "";
+ d[SI_basename].color.fg = COLOR_CYAN;
+ d[SI_basename].color.bg = COLOR_BLACK;
+ d[SI_basename].align = LEFT;
+ d[SI_basename].x = 35;
+ d[SI_basename].y = 7;
+ d[SI_basename].len = 65;
+
+ d[SI_status].prefix = "";
+ d[SI_status].postfix = " ";
+ d[SI_status].color.fg = COLOR_RED;
+ d[SI_status].color.bg = COLOR_BLACK;
+ d[SI_status].align = RIGHT;
+ d[SI_status].x = 0;
+ d[SI_status].y = 17;
+ d[SI_status].len = 11;
+
+ d[SI_status_flags].prefix = "(";
+ d[SI_status_flags].postfix = ")";
+ d[SI_status_flags].color.fg = COLOR_RED;
+ d[SI_status_flags].color.bg = COLOR_BLACK;
+ d[SI_status_flags].align = LEFT;
+ d[SI_status_flags].x = 11;
+ d[SI_status_flags].y = 17;
+ d[SI_status_flags].len = 10;
+
+ d[SI_image_id].prefix = "img: ";
+ d[SI_image_id].postfix = "";
+ d[SI_image_id].color.fg = COLOR_RED;
+ d[SI_image_id].color.bg = COLOR_BLACK;
+ d[SI_image_id].align = CENTER;
+ d[SI_image_id].x = 21;
+ d[SI_image_id].y = 17;
+ d[SI_image_id].len = 10;
+
+ d[SI_lyrics_id].prefix = "lyr: ";
+ d[SI_lyrics_id].postfix = "";
+ d[SI_lyrics_id].color.fg = COLOR_RED;
+ d[SI_lyrics_id].color.bg = COLOR_BLACK;
+ d[SI_lyrics_id].align = CENTER;
+ d[SI_lyrics_id].x = 31;
+ d[SI_lyrics_id].y = 17;
+ d[SI_lyrics_id].len = 11;
+
+ d[SI_format].prefix = "format: ";
+ d[SI_format].postfix = "";
+ d[SI_format].color.fg = COLOR_RED;
+ d[SI_format].color.bg = COLOR_BLACK;
+ d[SI_format].align = CENTER;
+ d[SI_format].x = 42;
+ d[SI_format].y = 17;
+ d[SI_format].len = 18;
+
+ d[SI_num_played].prefix = "#";
+ d[SI_num_played].postfix = "";
+ d[SI_num_played].color.fg = COLOR_RED;
+ d[SI_num_played].color.bg = COLOR_BLACK;
+ d[SI_num_played].align = LEFT;
+ d[SI_num_played].x = 60;
+ d[SI_num_played].y = 17;
+ d[SI_num_played].len = 5;
+
+ d[SI_bitrate].prefix = "";
+ d[SI_bitrate].postfix = "";
+ d[SI_bitrate].color.fg = COLOR_RED;
+ d[SI_bitrate].color.bg = COLOR_BLACK;
+ d[SI_bitrate].align = CENTER;
+ d[SI_bitrate].x = 65;
+ d[SI_bitrate].y = 17;
+ d[SI_bitrate].len = 13;
+
+ d[SI_frequency].prefix = "";
+ d[SI_frequency].postfix = "";
+ d[SI_frequency].color.fg = COLOR_RED;
+ d[SI_frequency].color.bg = COLOR_BLACK;
+ d[SI_frequency].align = CENTER;
+ d[SI_frequency].x = 78;
+ d[SI_frequency].y = 17;
+ d[SI_frequency].len = 10;
+
+ d[SI_score].prefix = "sc: ";
+ d[SI_score].postfix = "";
+ d[SI_score].color.fg = COLOR_RED;
+ d[SI_score].color.bg = COLOR_BLACK;
+ d[SI_score].align = CENTER;
+ d[SI_score].x = 88;
+ d[SI_score].y = 17;
+ d[SI_score].len = 10;
+
+ d[SI_audiod_status].prefix = "";
+ d[SI_audiod_status].postfix = "";
+ d[SI_audiod_status].color.fg = COLOR_MAGENTA;
+ d[SI_audiod_status].color.bg = COLOR_BLACK;
+ d[SI_audiod_status].align = CENTER;
+ d[SI_audiod_status].x = 0;
+ d[SI_audiod_status].y = 27;
+ d[SI_audiod_status].len = 5;
+
+ d[SI_decoder_flags].prefix = "[";
+ d[SI_decoder_flags].postfix = "]";
+ d[SI_decoder_flags].color.fg = COLOR_MAGENTA;
+ d[SI_decoder_flags].color.bg = COLOR_BLACK;
+ d[SI_decoder_flags].align = CENTER;
+ d[SI_decoder_flags].x = 5;
+ d[SI_decoder_flags].y = 27;
+ d[SI_decoder_flags].len = 10;
+
+ d[SI_mtime].prefix = "mod: ";
+ d[SI_mtime].postfix = "";
+ d[SI_mtime].color.fg = COLOR_MAGENTA;
+ d[SI_mtime].color.bg = COLOR_BLACK;
+ d[SI_mtime].align = CENTER;
+ d[SI_mtime].x = 15;
+ d[SI_mtime].y = 27;
+ d[SI_mtime].len = 22;
+
+ d[SI_file_size].prefix = "";
+ d[SI_file_size].postfix = "kb";
+ d[SI_file_size].color.fg = COLOR_MAGENTA;
+ d[SI_file_size].color.bg = COLOR_BLACK;
+ d[SI_file_size].align = CENTER;
+ d[SI_file_size].x = 37;
+ d[SI_file_size].y = 27;
+ d[SI_file_size].len = 10;
+
+ d[SI_channels].prefix = "";
+ d[SI_channels].postfix = "ch";
+ d[SI_channels].color.fg = COLOR_MAGENTA;
+ d[SI_channels].color.bg = COLOR_BLACK;
+ d[SI_channels].align = CENTER;
+ d[SI_channels].x = 47;
+ d[SI_channels].y = 27;
+ d[SI_channels].len = 5;
+
+ d[SI_last_played].prefix = "lp: ";
+ d[SI_last_played].postfix = "";
+ d[SI_last_played].color.fg = COLOR_MAGENTA;
+ d[SI_last_played].color.bg = COLOR_BLACK;
+ d[SI_last_played].align = CENTER;
+ d[SI_last_played].x = 52;
+ d[SI_last_played].y = 27;
+ d[SI_last_played].len = 21;
+
+ d[SI_num_chunks].prefix = "";
+ d[SI_num_chunks].postfix = "x";
+ d[SI_num_chunks].color.fg = COLOR_MAGENTA;
+ d[SI_num_chunks].color.bg = COLOR_BLACK;
+ d[SI_num_chunks].align = RIGHT;
+ d[SI_num_chunks].x = 73;
+ d[SI_num_chunks].y = 27;
+ d[SI_num_chunks].len = 11;
+
+ d[SI_chunk_time].prefix = "";
+ d[SI_chunk_time].postfix = "ms";
+ d[SI_chunk_time].color.fg = COLOR_MAGENTA;
+ d[SI_chunk_time].color.bg = COLOR_BLACK;
+ d[SI_chunk_time].align = LEFT;
+ d[SI_chunk_time].x = 84;
+ d[SI_chunk_time].y = 27;
+ d[SI_chunk_time].len = 8;
+
+ d[SI_amplification].prefix = "amp:";
+ d[SI_amplification].postfix = "";
+ d[SI_amplification].color.fg = COLOR_MAGENTA;
+ d[SI_amplification].color.bg = COLOR_BLACK;
+ d[SI_amplification].align = RIGHT;
+ d[SI_amplification].x = 92;
+ d[SI_amplification].y = 27;
+ d[SI_amplification].len = 8;
+
+ d[SI_techinfo].prefix = "";
+ d[SI_techinfo].postfix = "";
+ d[SI_techinfo].color.fg = COLOR_GREEN;
+ d[SI_techinfo].color.bg = COLOR_BLACK;
+ d[SI_techinfo].align = CENTER;
+ d[SI_techinfo].x = 0;
+ d[SI_techinfo].y = 43;
+ d[SI_techinfo].len = 100;
+
+ d[SI_title].prefix = "";
+ d[SI_title].postfix = ",";
+ d[SI_title].color.fg = COLOR_GREEN;
+ d[SI_title].color.bg = COLOR_BLACK;
+ d[SI_title].align = RIGHT;
+ d[SI_title].x = 0;
+ d[SI_title].y = 53;
+ d[SI_title].len = 45;
+
+ d[SI_artist].prefix = " by ";
+ d[SI_artist].postfix = "";
+ d[SI_artist].color.fg = COLOR_GREEN;
+ d[SI_artist].color.bg = COLOR_BLACK;
+ d[SI_artist].align = LEFT;
+ d[SI_artist].x = 45;
+ d[SI_artist].y = 53;
+ d[SI_artist].len = 45;
+
+ d[SI_year].prefix = "(";
+ d[SI_year].postfix = ")";
+ d[SI_year].color.fg = COLOR_GREEN;
+ d[SI_year].color.bg = COLOR_BLACK;
+ d[SI_year].align = RIGHT;
+ d[SI_year].x = 90;
+ d[SI_year].y = 53;
+ d[SI_year].len = 10;
+
+ d[SI_album].prefix = "A: ";
+ d[SI_album].postfix = ",";
+ d[SI_album].color.fg = COLOR_GREEN;
+ d[SI_album].color.bg = COLOR_BLACK;
+ d[SI_album].align = RIGHT;
+ d[SI_album].x = 0;
+ d[SI_album].y = 63;
+ d[SI_album].len = 50;
+
+ d[SI_comment].prefix = " C: ";
+ d[SI_comment].postfix = "";
+ d[SI_comment].color.fg = COLOR_GREEN;
+ d[SI_comment].color.bg = COLOR_BLACK;
+ d[SI_comment].align = LEFT;
+ d[SI_comment].x = 50;
+ d[SI_comment].y = 63;
+ d[SI_comment].len = 50;
+
+ d[SI_afs_mode].prefix = "";
+ d[SI_afs_mode].postfix = "";
+ d[SI_afs_mode].color.fg = COLOR_YELLOW;
+ d[SI_afs_mode].color.bg = COLOR_BLACK;
+ d[SI_afs_mode].align = CENTER;
+ d[SI_afs_mode].x = 0;
+ d[SI_afs_mode].y = 77;
+ d[SI_afs_mode].len = 100;
+
+ d[SI_attributes_txt].prefix = "";
+ d[SI_attributes_txt].postfix = "";
+ d[SI_attributes_txt].color.fg = COLOR_YELLOW;
+ d[SI_attributes_txt].color.bg = COLOR_BLACK;
+ d[SI_attributes_txt].align = CENTER;
+ d[SI_attributes_txt].x = 0;
+ d[SI_attributes_txt].y = 87;
+ d[SI_attributes_txt].len = 100;
+
+ d[SI_directory].prefix = "dir: ";
+ d[SI_directory].postfix = "";
+ d[SI_directory].color.fg = COLOR_YELLOW;
+ d[SI_directory].color.bg = COLOR_BLACK;
+ d[SI_directory].align = CENTER;
+ d[SI_directory].x = 0;
+ d[SI_directory].y = 97;
+ d[SI_directory].len = 100;
}
struct theme_description {
$(lls_suite_dir)/%.m4d: $(lls_m4_dir)/%.suite.m4 | $(lls_suite_dir)
@[ -z "$(Q)" ] || echo 'M4D $<'
-
$(Q) $(M4) -Pg -I $(lls_m4_include_dir) -s $< \
| awk '{if ($$1 ~ /#line/) {gsub(/"/, "", $$3); if ($$3 != "$<") \
print "$(lls_suite_dir)/$(*F).suite: " $$3}}' | sort | uniq > $@
$(lls_suite_dir)/%.suite: $(lls_m4_dir)/%.suite.m4 | $(lls_suite_dir)
+ @[ -z "$(Q)" ] || echo 'M4 $<'
$(Q) $(M4) -Pg -I $(lls_m4_include_dir) -D GIT_VERSION=$(GIT_VERSION) \
-D COPYRIGHT_YEAR=$(COPYRIGHT_YEAR) -D LOGLEVELS=$(LOGLEVELS) \
$< > $@
$(lls_suite_dir)/%.lsg.c: $(lls_suite_dir)/%.suite
@[ -z "$(Q)" ] || echo 'LSGC $<'
- $(Q) lopsubgen --gen-c --output-dir $(lls_suite_dir) < $<
+ $(Q) $(LOPSUBGEN) --gen-c --output-dir $(lls_suite_dir) < $<
$(lls_suite_dir)/%.lsg.h: $(lls_suite_dir)/%.suite
@[ -z "$(Q)" ] || echo 'LSGH $<'
- $(Q) lopsubgen --gen-header --output-dir $(lls_suite_dir) < $<
+ $(Q) $(LOPSUBGEN) --gen-header --output-dir $(lls_suite_dir) < $<
$(lls_suite_dir)/%.lsg.man: $(lls_suite_dir)/%.suite
@[ -z "$(Q)" ] || echo 'LSGM $<'
- $(Q) lopsubgen --gen-man --output-dir $(lls_suite_dir) < $<
+ $(Q) $(LOPSUBGEN) --gen-man --output-dir $(lls_suite_dir) < $<
$(object_dir)/%.o: $(lls_suite_dir)/%.c | $(object_dir)
@[ -z "$(Q)" ] || echo 'CC $<'
also given), chunk time and chunk offsets.
[/help]
- [option full-path]
- short_opt = F
- summary = list full paths, match full paths against patterns
- [help]
- This option is the default, so it does nothing. Deprecated as of
- v0.6.0, scheduled for removal in v0.6.1.
- [/help]
[option basename]
short_opt = b
summary = list and match basenames only
#include "afh.h"
#include "afs.h"
#include "list.h"
-#include "ipc.h"
#include "mm.h"
-#include "sideband.h"
#include "mood.h"
-#include "sched.h"
/**
* Contains statistical data of the currently admissible audio files.
ret = 1;
out:
free_argv(argv);
- if (ret >= 0)
- return ret;
- if (mi) {
+ if (mi && (ret < 0 || !mlpd->m)) { /* mi was not added to any list */
free(mi->parser_data);
free(mi);
}
{
int ret;
struct private_vorbis_data pvd;
- struct ogg_afh_callback_info vorbis_callback_info = {
+ struct oac_callback_info vorbis_callback_info = {
.packet_callback = vorbis_packet_callback,
.private_data = &pvd,
};
vorbis_info_init(&pvd.vi);
vorbis_comment_init(&pvd.vc);
- ret = ogg_get_file_info(map, numbytes, afhi, &vorbis_callback_info);
+ ret = oac_get_file_info(map, numbytes, afhi, &vorbis_callback_info);
vorbis_info_clear(&pvd.vi);
vorbis_comment_clear(&pvd.vc);
return ret;
}
-struct vorbis_get_header_data {
- ogg_stream_state os;
- char *buf;
- size_t len;
-};
-
-static void add_ogg_page(ogg_page *og, struct vorbis_get_header_data *vghd)
-{
- size_t old_len = vghd->len;
- size_t new_len = vghd->len + og->header_len + og->body_len;
- char *buf = para_realloc(vghd->buf, new_len), *p = buf + old_len;
-
- memcpy(p, og->header, og->header_len);
- memcpy(p + og->header_len, og->body, og->body_len);
- vghd->buf = buf;
- vghd->len = new_len;
- PARA_DEBUG_LOG("header/body/old/new: %li/%li/%zu/%zu\n",
- og->header_len, og->body_len, old_len, new_len);
-}
-
static int vorbis_get_header_callback(ogg_packet *packet, int packet_num,
int serial, __a_unused struct afh_info *afhi, void *private_data)
{
int ret;
- struct vorbis_get_header_data *vghd = private_data;
- ogg_page og;
+ struct oac_custom_header *h = private_data;
static unsigned char dummy_packet[] = {
0x03,
'v', 'o', 'r', 'b', 'i', 's',
};
PARA_DEBUG_LOG("processing ogg packet #%d\n", packet_num);
- if (packet_num > 2)
- return 0;
if (packet_num == 0) {
- ogg_stream_init(&vghd->os, serial);
- ret = ogg_stream_packetin(&vghd->os, packet);
+ oac_custom_header_init(serial, h);
+ ret = oac_custom_header_append(packet, h);
if (ret < 0)
- goto out;
- ret = -E_OGG_STREAM_FLUSH;
- if (ogg_stream_flush(&vghd->os, &og) == 0)
- goto out;
- add_ogg_page(&og, vghd);
+ return ret;
+ oac_custom_header_flush(h);
return 1;
}
if (packet_num == 1) {
PARA_INFO_LOG("replacing metadata packet\n");
replacement.packet = dummy_packet;
replacement.bytes = sizeof(dummy_packet);
- ret = ogg_stream_packetin(&vghd->os, &replacement);
- if (ret >= 0)
- return 1;
- ret = -E_OGG_PACKET_IN;
- goto out;
+ ret = oac_custom_header_append(&replacement, h);
+ return ret < 0? ret : 1;
}
- ret = -E_OGG_PACKET_IN;
- if (ogg_stream_packetin(&vghd->os, packet) < 0)
- goto out;
- while (ogg_stream_flush(&vghd->os, &og))
- add_ogg_page(&og, vghd);
- ret = 0;
-out:
- ogg_stream_clear(&vghd->os);
- return ret;
+ assert(packet_num == 2);
+ ret = oac_custom_header_append(packet, h);
+ if (ret < 0)
+ return ret;
+ oac_custom_header_flush(h);
+ return 0;
}
static void vorbis_get_header(void *map, size_t mapsize, char **buf,
size_t *len)
{
int ret;
- struct vorbis_get_header_data vghd = {.len = 0};
- struct ogg_afh_callback_info cb = {
+ struct oac_custom_header *h = oac_custom_header_new();
+ struct oac_callback_info cb = {
.packet_callback = vorbis_get_header_callback,
- .private_data = &vghd,
+ .private_data = h,
};
- ret = ogg_get_file_info(map, mapsize, NULL, &cb);
- if (ret < 0)
- goto fail;
- *buf = vghd.buf;
- *len = vghd.len;
- PARA_INFO_LOG("created %zu byte ogg vorbis header\n", *len);
- return;
-fail:
- PARA_ERROR_LOG("%s\n", para_strerror(-ret));
+ ret = oac_get_file_info(map, mapsize, NULL, &cb);
+ *len = oac_custom_header_get(buf, h);
+ if (ret < 0) {
+ PARA_ERROR_LOG("could not create ogg/vorbis header: %s\n",
+ para_strerror(-ret));
+ free(*buf);
+ *buf = NULL;
+ *len = 0;
+ } else
+ PARA_INFO_LOG("created %zu byte ogg vorbis header\n", *len);
}
static int vorbis_make_meta_packet(struct taginfo *tags, ogg_packet *result)
ret = vorbis_make_meta_packet(tags, &packet);
if (ret < 0)
return ret;
- ret = ogg_rewrite_tags(map, mapsize, output_fd, (char *)packet.packet,
+ ret = oac_rewrite_tags(map, mapsize, output_fd, (char *)packet.packet,
packet.bytes);
free(packet.packet);
return ret;
/* Taken from decoder_example.c of libvorbis-1.2.3. */
static int process_packets_2_and_3(ogg_sync_state *oss,
ogg_stream_state *stream, struct afh_info *afhi,
- struct ogg_afh_callback_info *ci)
+ struct oac_callback_info *ci)
{
ogg_page page;
ogg_packet packet;
}
static int process_ogg_packets(ogg_sync_state *oss, struct afh_info *afhi,
- struct ogg_afh_callback_info *ci)
+ struct oac_callback_info *ci)
{
ogg_packet packet;
ogg_stream_state stream;
*
* \return Standard.
*/
-int ogg_get_file_info(char *map, size_t numbytes, struct afh_info *afhi,
- struct ogg_afh_callback_info *ci)
+int oac_get_file_info(char *map, size_t numbytes, struct afh_info *afhi,
+ struct oac_callback_info *ci)
{
ogg_sync_state oss;
ogg_page op;
*
* \return Standard.
*/
-int ogg_rewrite_tags(const char *map, size_t map_sz, int fd,
+int oac_rewrite_tags(const char *map, size_t map_sz, int fd,
char *meta_packet, size_t meta_sz)
{
ogg_sync_state oss_in, oss_out;
ogg_stream_clear(so);
return ret;
}
+
+/* Structure for providing custom headers for streaming. */
+struct oac_custom_header {
+ char *buf;
+ size_t len;
+ ogg_stream_state oss;
+};
+
+/**
+ * Allocate and return a custom header structure.
+ *
+ * For some audio codecs which employ the ogg container format, the server side
+ * wants to replace the meta tags at the beginning of the file because they are
+ * not needed for streaming and can be arbitrary large. The structure returned
+ * by this function is typically used as the ->private field of struct \ref
+ * oac_callback_info for \ref oac_get_file_info(). This allows the audio format
+ * handler to set up a custom header which is identical to the original header,
+ * but with the meta data part replaced by fixed length dummy contents.
+ *
+ * \return The returned memory must be initialized with the serial number of
+ * the ogg stream before ogg packets can be submitted to it. This is not done
+ * here because the header structure is allocated before \ref
+ * oac_get_file_info() is called, and the serial number is not known at this
+ * point.
+ *
+ * \sa \ref oac_custom_header_init().
+ */
+struct oac_custom_header *oac_custom_header_new(void)
+{
+ return para_calloc(sizeof(struct oac_custom_header));
+}
+
+/**
+ * Set the serial number of an allocated header structure.
+ *
+ * \param serial Passed to the callback function.
+ * \param h As returned from \ref oac_custom_header_new().
+ *
+ * This function must be called before any packets are submitted.
+ */
+void oac_custom_header_init(int serial, struct oac_custom_header *h)
+{
+ ogg_stream_init(&h->oss, serial);
+}
+
+/**
+ * Submit an ogg packet to a custom header structure.
+ *
+ * \param op The packet to append.
+ * \param h Must be initialized.
+ *
+ * The packet may be the one which was passed to the callback, or a completely
+ * different one, like a dummy metadata packet.
+ *
+ * \return Standard.
+ */
+int oac_custom_header_append(ogg_packet *op, struct oac_custom_header *h)
+{
+ return ogg_stream_packetin(&h->oss, op) < 0? -E_OGG_PACKET_IN : 1;
+}
+
+/**
+ * Force remaining packets into an ogg page.
+ *
+ * \param h Should contain submitted but not yet flushed packets.
+ *
+ * This is called after the first packet has been submitted with \ref
+ * oac_custom_header_append() to make sure the first ogg page contains only
+ * this packet. Also when header processing is complete, the callbacks call
+ * this to force the previously submitted packets into a page.
+ */
+void oac_custom_header_flush(struct oac_custom_header *h)
+{
+ ogg_page og;
+
+ while (ogg_stream_flush(&h->oss, &og)) {
+ size_t len = og.header_len + og.body_len;
+ h->buf = para_realloc(h->buf, h->len + len);
+ memcpy(h->buf + h->len, og.header, og.header_len);
+ memcpy(h->buf + h->len + og.header_len, og.body, og.body_len);
+ h->len += len;
+ }
+}
+
+/**
+ * Return the custom header buffer and deallocate resources.
+ *
+ * This is called after the ogg packets which comprise the header have been
+ * submitted and flushed.
+ *
+ * \param buf Result pointer.
+ * \param h Must not be used any more after the call.
+ *
+ * \return The size of the header. This is the sum of the sizes of all ogg
+ * pages that have been flushed out.
+ */
+size_t oac_custom_header_get(char **buf, struct oac_custom_header *h)
+{
+ size_t ret = h->len;
+
+ *buf = h->buf;
+ ogg_stream_clear(&h->oss);
+ free(h);
+ return ret;
+}
* handlers that use the ogg container format.
*/
+struct oac_custom_header *oac_custom_header_new(void);
+void oac_custom_header_init(int serial, struct oac_custom_header *h);
+int oac_custom_header_append(ogg_packet *op, struct oac_custom_header *h);
+void oac_custom_header_flush(struct oac_custom_header *h);
+size_t oac_custom_header_get(char **buf, struct oac_custom_header *h);
+
/**
* Callback structure provided by audio format handlers.
*
* function whose purpose is to extract the meta information about the audio
* file from the first few ogg packets of the bitstream.
*/
-struct ogg_afh_callback_info {
+struct oac_callback_info {
/**
* ogg_get_file_info() calls this function for the first three ogg
* packets, or until the callback returns a non-positive value. If it
void *private_data;
};
-int ogg_get_file_info(char *map, size_t numbytes, struct afh_info *afhi,
- struct ogg_afh_callback_info *ci);
-int ogg_rewrite_tags(const char *map, size_t mapsize, int fd,
+int oac_get_file_info(char *map, size_t numbytes, struct afh_info *afhi,
+ struct oac_callback_info *ci);
+int oac_rewrite_tags(const char *map, size_t mapsize, int fd,
char *meta_packet, size_t meta_sz);
return 1;
}
+/*
+ * Ogg/Opus has two mandatory header packets:
+ *
+ * 1. ID header (identifies the stream as Opus). Dedicated "BOS" ogg page.
+ * 2. Comment header (metadata). May span multiple pages.
+ *
+ * See doc/draft-ietf-codec-oggopus.xml in the opus source tree for details.
+ */
static int opus_packet_callback(ogg_packet *packet, int packet_num,
__a_unused int serial, struct afh_info *afhi,
void *private_data)
int ret, ms;
struct opus_header oh = {.version = 0};
- struct ogg_afh_callback_info opus_callback_info = {
+ struct oac_callback_info opus_callback_info = {
.packet_callback = opus_packet_callback,
.private_data = &oh,
};
- ret = ogg_get_file_info(map, numbytes, afhi, &opus_callback_info);
+ ret = oac_get_file_info(map, numbytes, afhi, &opus_callback_info);
if (ret < 0)
return ret;
ret = (afhi->chunk_table[afhi->chunks_total] - afhi->chunk_table[0]) * 8; /* bits */
int ret;
meta_sz = opus_make_meta_packet(tags, &meta_packet);
- ret = ogg_rewrite_tags(map, mapsize, output_fd, meta_packet, meta_sz);
+ ret = oac_rewrite_tags(map, mapsize, output_fd, meta_packet, meta_sz);
free(meta_packet);
return ret;
}
+/*
+ * See doc/draft-ietf-codec-oggopus.xml in the opus source tree for details
+ * about the format of the comment header.
+ */
+static int opus_get_header_callback(ogg_packet *packet, int packet_num,
+ int serial, __a_unused struct afh_info *afhi, void *private_data)
+{
+ struct oac_custom_header *h = private_data;
+ int ret;
+ static unsigned char dummy_tags[] = { /* a minimal comment header */
+ 'O', 'p', 'u', 's', 'T', 'a', 'g', 's',
+ 0x06, 0x00, 0x00, 0x00, /* vendor string length */
+ 'd', 'u', 'm', 'm', 'y', '\0', /* vendor string */
+ 0x00, 0x00, 0x00, 0x00, /* user comment list length */
+ };
+ ogg_packet replacement;
+
+ if (packet_num == 0) {
+ oac_custom_header_init(serial, h);
+ ret = oac_custom_header_append(packet, h);
+ if (ret < 0)
+ return ret;
+ oac_custom_header_flush(h);
+ return 1;
+ }
+ assert(packet_num == 1);
+ PARA_INFO_LOG("replacing metadata packet\n");
+ replacement = *packet;
+ replacement.packet = dummy_tags;
+ replacement.bytes = sizeof(dummy_tags);
+ ret = oac_custom_header_append(&replacement, h);
+ if (ret < 0)
+ return ret;
+ oac_custom_header_flush(h);
+ return 0;
+}
+
+static void opus_get_header(void *map, size_t mapsize, char **buf,
+ size_t *len)
+{
+ int ret;
+ struct oac_custom_header *h = oac_custom_header_new();
+ struct oac_callback_info cb = {
+ .packet_callback = opus_get_header_callback,
+ .private_data = h,
+ };
+
+ ret = oac_get_file_info(map, mapsize, NULL, &cb);
+ *len = oac_custom_header_get(buf, h);
+ if (ret < 0) {
+ PARA_ERROR_LOG("could not create custom header: %s\n",
+ para_strerror(-ret));
+ free(*buf);
+ *buf = NULL;
+ *len = 0;
+ } else
+ PARA_INFO_LOG("created %zu byte ogg/opus header\n", *len);
+}
+
/**
* The init function of the ogg/opus audio format handler.
*
void opus_afh_init(struct audio_format_handler *afh)
{
afh->get_file_info = opus_get_file_info,
+ afh->get_header = opus_get_header;
afh->suffixes = opus_suffixes;
afh->rewrite_tags = opus_rewrite_tags;
}
struct timeval *result);
struct timeval *clock_get_realtime(struct timeval *tv);
-/** The enum of all status items. */
-enum status_items {STATUS_ITEM_ENUM NUM_STAT_ITEMS};
-extern const char *status_item_list[];
-/** Loop over each status item. */
-#define FOR_EACH_STATUS_ITEM(i) for (i = 0; i < NUM_STAT_ITEMS; i++)
-int for_each_stat_item(char *item_buf, size_t num_bytes,
- int (*item_handler)(int, char *));
-
-
/**
* Return a random non-negative integer in an interval.
*
#define PARA_ERROR_LOG(f,...) para_log(LL_ERROR, "%s: " f, __FUNCTION__, ## __VA_ARGS__)
#define PARA_CRIT_LOG(f,...) para_log(LL_CRIT, "%s: " f, __FUNCTION__, ## __VA_ARGS__)
#define PARA_EMERG_LOG(f,...) para_log(LL_EMERG, "%s: " f, __FUNCTION__, ## __VA_ARGS__)
+
+#define STATUS_ITEMS \
+ STATUS_ITEM(basename) \
+ STATUS_ITEM(status) \
+ STATUS_ITEM(num_played) \
+ STATUS_ITEM(mtime) \
+ STATUS_ITEM(bitrate) \
+ STATUS_ITEM(frequency) \
+ STATUS_ITEM(file_size) \
+ STATUS_ITEM(status_flags) \
+ STATUS_ITEM(format) \
+ STATUS_ITEM(score) \
+ STATUS_ITEM(techinfo) \
+ STATUS_ITEM(afs_mode) \
+ STATUS_ITEM(attributes_txt) \
+ STATUS_ITEM(decoder_flags) \
+ STATUS_ITEM(audiod_status) \
+ STATUS_ITEM(play_time) \
+ STATUS_ITEM(attributes_bitmap) \
+ STATUS_ITEM(offset) \
+ STATUS_ITEM(seconds_total) \
+ STATUS_ITEM(stream_start) \
+ STATUS_ITEM(current_time) \
+ STATUS_ITEM(audiod_uptime) \
+ STATUS_ITEM(image_id) \
+ STATUS_ITEM(lyrics_id) \
+ STATUS_ITEM(duration) \
+ STATUS_ITEM(directory) \
+ STATUS_ITEM(lyrics_name) \
+ STATUS_ITEM(image_name) \
+ STATUS_ITEM(path) \
+ STATUS_ITEM(hash) \
+ STATUS_ITEM(channels) \
+ STATUS_ITEM(last_played) \
+ STATUS_ITEM(num_chunks) \
+ STATUS_ITEM(chunk_time) \
+ STATUS_ITEM(amplification) \
+ STATUS_ITEM(artist) \
+ STATUS_ITEM(title) \
+ STATUS_ITEM(year) \
+ STATUS_ITEM(album) \
+ STATUS_ITEM(comment) \
+ STATUS_ITEM(max_chunk_size) \
+
+#define STATUS_ITEM(_name) SI_ ##_name,
+enum status_items {STATUS_ITEMS NUM_STAT_ITEMS};
+#undef STATUS_ITEM
+#define STATUS_ITEM(_name) #_name,
+
+extern const char *status_item_list[];
+/** Loop over each status item. */
+#define FOR_EACH_STATUS_ITEM(i) for (i = 0; i < NUM_STAT_ITEMS; i++)
+int for_each_stat_item(char *item_buf, size_t num_bytes,
+ int (*item_handler)(int, char *));
/** \file portable_io.h Inline functions for binary IO. */
-static inline uint64_t read_portable(unsigned bits, const char *buf)
+static inline uint64_t read_portable(unsigned bits, const void *buf)
{
uint64_t ret = 0;
int i, num_bytes = bits / 8;
+ const uint8_t *p = (typeof(p))buf;
for (i = 0; i < num_bytes; i++) {
- unsigned char c = buf[i];
+ unsigned char c = p[i];
ret += ((uint64_t)c << (8 * i));
}
return ret;
}
-static inline uint64_t read_portable_be(unsigned bits, const char *buf)
+static inline uint64_t read_portable_be(unsigned bits, const void *buf)
{
uint64_t ret = 0;
int i, num_bytes = bits / 8;
+ const uint8_t *p = (typeof(p))buf;
for (i = 0; i < num_bytes; i++) {
- unsigned char c = buf[i];
+ unsigned char c = p[i];
ret += ((uint64_t)c << (8 * (num_bytes - i - 1)));
}
return ret;
}
-static inline uint64_t read_u64(const char *buf)
+static inline uint64_t read_u64(const void *buf)
{
return read_portable(64, buf);
}
-static inline uint32_t read_u32(const char *buf)
+static inline uint32_t read_u32(const void *buf)
{
return read_portable(32, buf);
}
-static inline uint16_t read_u16(const char *buf)
+static inline uint16_t read_u16(const void *buf)
{
return read_portable(16, buf);
}
-static inline uint8_t read_u8(const char *buf)
+static inline uint8_t read_u8(const void *buf)
{
return read_portable(8, buf);
}
-static inline uint64_t read_u64_be(const char *buf)
+static inline uint64_t read_u64_be(const void *buf)
{
return read_portable_be(64, buf);
}
-static inline uint32_t read_u32_be(const char *buf)
+static inline uint32_t read_u32_be(const void *buf)
{
return read_portable_be(32, buf);
}
-static inline uint16_t read_u16_be(const char *buf)
+static inline uint16_t read_u16_be(const void *buf)
{
return read_portable_be(16, buf);
}
static inline void write_portable(unsigned bits, char *buf, uint64_t val)
{
int i, num_bytes = bits / 8;
+ uint8_t *p = (typeof(p))buf;
+
for (i = 0; i < num_bytes; i++) {
- buf[i] = val & 0xff;
+ p[i] = val & 0xff;
val = val >> 8;
}
}
static inline void write_portable_be(unsigned bits, char *buf, uint64_t val)
{
int i, num_bytes = bits / 8;
+ uint8_t *p = (typeof(p))buf;
+
for (i = 0; i < num_bytes; i++) {
- buf[num_bytes - i - 1] = val & 0xff;
+ p[num_bytes - i - 1] = val & 0xff;
val = val >> 8;
}
}
-static inline void write_u64(char *buf, uint64_t val)
+static inline void write_u64(void *buf, uint64_t val)
{
write_portable(64, buf, val);
}
-static inline void write_u32(char *buf, uint32_t val)
+static inline void write_u32(void *buf, uint32_t val)
{
write_portable(32, buf, (uint64_t) val);
}
-static inline void write_u16(char *buf, uint16_t val)
+static inline void write_u16(void *buf, uint16_t val)
{
write_portable(16, buf, (uint64_t) val);
}
-static inline void write_u8(char *buf, uint8_t val)
+static inline void write_u8(void *buf, uint8_t val)
{
write_portable(8, buf, (uint64_t) val);
}
-static inline void write_u64_be(char *buf, uint64_t val)
+static inline void write_u64_be(void *buf, uint64_t val)
{
write_portable_be(64, buf, val);
}
-static inline void write_u32_be(char *buf, uint32_t val)
+static inline void write_u32_be(void *buf, uint32_t val)
{
write_portable_be(32, buf, (uint64_t) val);
}
-static inline void write_u16_be(char *buf, uint16_t val)
+static inline void write_u16_be(void *buf, uint16_t val)
{
write_portable_be(16, buf, (uint64_t) val);
}
goto free_cf;
if (ret == -ERRNO_TO_PARA_ERROR(ENOENT) && OPT_GIVEN(CONFIG_FILE))
goto free_cf;
- ret = 0;
server_lpr = cmdline_lpr;
goto success;
}
if (reload) /* config file overrides command line */
ret = lls(lls_merge(cf_lpr, cmdline_lpr, CMD_PTR, &merged_lpr,
&errctx));
- else /* command line options overrride config file options */
+ else /* command line options override config file options */
ret = lls(lls_merge(cmdline_lpr, cf_lpr, CMD_PTR, &merged_lpr,
&errctx));
lls_free_parse_result(cf_lpr, CMD_PTR);
ret = para_accept(sct->listen_fd, &s->rfds, NULL, 0, &new_fd);
if (ret <= 0)
goto out;
- peer_name = remote_name(new_fd);
- PARA_INFO_LOG("got connection from %s, forking\n", peer_name);
mmd->num_connects++;
mmd->active_connections++;
/*
/* parent keeps accepting connections */
return 0;
}
+ peer_name = remote_name(new_fd);
+ PARA_INFO_LOG("accepted connection from %s\n", peer_name);
/* mmd might already have changed at this point */
free(chunk_table);
alarm(ALARM_TIMEOUT);
init_signal_task();
para_unblock_signal(SIGCHLD);
PARA_NOTICE_LOG("initializing virtual streaming system\n");
- init_vss_task(afs_socket, &sched);
+ vss_init(afs_socket, &sched);
init_server_command_task(argc, argv);
if (daemon_pipe >= 0) {
if (write(daemon_pipe, "\0", 1) < 0) {
* This function creates a pipe, the signal pipe, to deliver pending
* signals to the application (Bernstein's trick). It should be called
* during the application's startup part, followed by subsequent calls
- * to para_install_sighandler() for each signal that should be caught.
+ * to \ref para_install_sighandler() for each signal that should be caught.
*
* A generic signal handler is used for all signals simultaneously. When a
* signal arrives, the signal handler writes the number of the signal received
* by checking if the file descriptor of the other end of the signal pipe is
* ready for reading, see select(2).
*
- * \return This function either succeeds or calls exit(2) to terminate the
+ * \return This function either succeeds or calls exit(3) to terminate the
* current process. On success, a signal task structure is returned.
*/
struct signal_task *signal_init_or_die(void)
struct afh_info *afhi)
{
struct private_spx_data psd;
- struct ogg_afh_callback_info spx_callback_info = {
+ struct oac_callback_info spx_callback_info = {
.packet_callback = spx_packet_callback,
.private_data = &psd,
};
memset(&psd, 0, sizeof(psd));
- return ogg_get_file_info(map, numbytes, afhi, &spx_callback_info);
+ return oac_get_file_info(map, numbytes, afhi, &spx_callback_info);
}
static size_t spx_make_meta_packet(struct taginfo *tags, char **result)
int ret;
meta_sz = spx_make_meta_packet(tags, &meta_packet);
- ret = ogg_rewrite_tags(map, mapsize, output_fd, meta_packet, meta_sz);
+ ret = oac_rewrite_tags(map, mapsize, output_fd, meta_packet, meta_sz);
free(meta_packet);
return ret;
}
exit(EXIT_FAILURE);
}
sit->fd_flags = ret;
- sit->must_set_nonblock_flag = (sit->fd_flags & O_NONBLOCK) == 0;
+ sit->must_set_nonblock_flag = (sit->fd_flags & O_NONBLOCK) == 0
+ && !isatty(STDIN_FILENO);
sit->task = task_register(&ti, s);
}
exit(EXIT_FAILURE);
}
sot->fd_flags = ret;
- sot->must_set_nonblock_flag = (sot->fd_flags & O_NONBLOCK) == 0;
+ sot->must_set_nonblock_flag = (sot->fd_flags & O_NONBLOCK) == 0
+ && !isatty(STDOUT_FILENO);
sot->task = task_register(&ti, s);
}
line_handler_t *line_handler, void *private_data);
/**
- * Write the contents of a status item to a para_buffer.
- *
- * \param b The para_buffer.
- * \param n The number of the status item.
- * \param f A format string.
- *
- * \return The return value of the underlying call to para_printf().
- */
+ * Write the contents of a status item to a para_buffer.
+ *
+ * \param b The para_buffer.
+ * \param n The number of the status item.
+ * \param f A format string.
+ *
+ * \return The return value of the underlying call to \ref para_printf().
+ */
#define WRITE_STATUS_ITEM(b, n, f, ...) (\
{ \
if ((b)->flags & PBF_SIZE_PREFIX) { \
let i++
commands[$i]="ls"
required_objects[$i]='ogg_afh'
-cmdline[$i]="ls -l=v -F ${oggs[@]}"
+cmdline[$i]="ls -l=v ${oggs[@]}"
good[$i]='^attributes_txt: 33'
let i++
PARA_NOTICE_LOG("sending FEC EOF\n");
len = vss_get_fec_eof_packet(&buf);
/* Ignore write() errors since we are closing the target anyway. */
- if (write(sc->fd, buf, len) == len)
- ut->sent_fec_eof = true;
+ if (write(sc->fd, buf, len))
+ do_nothing; /* avoid "ignoring return value" warning */
+ ut->sent_fec_eof = true;
}
static void udp_delete_target(struct sender_client *sc, const char *msg)
}
/**
- * Initialize the list of users allowed to connect to to para_server.
+ * Initialize the list of users allowed to connect to para_server.
*
* \param user_list_file The file containing access information.
*
*/
static void vss_send(struct vss_task *vsst)
{
- int i, fec_active = 0;
+ int i;
+ bool fec_active = false;
struct timeval due;
struct fec_client *fc, *tmp_fc;
return;
if (chk_barrier("eof", &vsst->eof_barrier, &due, 1) < 0)
return;
- if (chk_barrier("data send", &vsst->data_send_barrier,
- &due, 1) < 0)
+ if (chk_barrier("data send", &vsst->data_send_barrier, &due, 1) < 0)
return;
list_for_each_entry_safe(fc, tmp_fc, &fec_client_list, node) {
if (fc->state == FEC_STATE_DISABLED)
continue;
if (!next_slice_is_due(fc, NULL)) {
- fec_active = 1;
+ fec_active = true;
continue;
}
if (compute_next_fec_slice(fc, vsst) <= 0)
fc->current_slice_num++;
fc->fcp->send_fec(fc->sc, (char *)fc->enc_buf,
fc->group.slice_bytes + FEC_HEADER_SIZE);
- fec_active = 1;
+ fec_active = true;
}
if (mmd->current_chunk >= mmd->afd.afhi.chunks_total) { /* eof */
if (!fec_active)
mmd->events++;
set_mmd_offset();
}
- /*
- * We call the send function also in case of empty chunks as
- * they might have still some data queued which can be sent in
- * this case.
- */
vss_get_chunk(mmd->current_chunk, vsst, &buf, &len);
for (i = 0; senders[i].name; i++) {
+ /*
+ * We call ->send() even if len is zero because senders
+ * might have data queued which can be sent now.
+ */
if (!senders[i].send)
continue;
senders[i].send(mmd->current_chunk, mmd->chunks_sent,
buf, len, vsst->header_buf, vsst->header_len);
}
- /*
- * Prefault next chunk(s)
- *
- * If the backing device of the memory-mapped audio file is
- * slow and read-ahead is turned off or prevented for some
- * reason, e.g. due to memory pressure, it may take much longer
- * than the chunk interval to get the next chunk on the wire,
- * causing buffer underruns on the client side. Mapping the
- * file with MAP_POPULATE seems to help a bit, but it does not
- * eliminate the delays completely. Moreover, it is supported
- * only on Linux. So we do our own read-ahead here.
- */
- if (mmd->current_chunk > 0) { /* chunk 0 might be on the heap */
- buf += len;
- for (i = 0; i < 5 && buf < vsst->map + vsst->mapsize; i++) {
- __a_unused volatile char x = *buf;
- buf += 4096;
- }
- }
mmd->chunks_sent++;
mmd->current_chunk++;
}
* This also initializes all supported senders and starts streaming
* if the --autoplay command line flag was given.
*/
-void init_vss_task(int afs_socket, struct sched *s)
+void vss_init(int afs_socket, struct sched *s)
{
static struct vss_task vss_task_struct, *vsst = &vss_task_struct;
int i;
- char *hn = para_hostname(), *home = para_homedir();
long unsigned announce_time = OPT_UINT32_VAL(ANNOUNCE_TIME),
autoplay_delay = OPT_UINT32_VAL(AUTOPLAY_DELAY);
vsst->header_interval.tv_sec = 5; /* should this be configurable? */
PARA_NOTICE_LOG("initializing %s sender\n", senders[i].name);
senders[i].init(&senders[i]);
}
- free(hn);
- free(home);
mmd->sender_cmd_data.cmd_num = -1;
if (OPT_GIVEN(AUTOPLAY)) {
struct timeval tmp;
/** \file vss.h Exported functions from vss.c (para_server). */
-void init_vss_task(int afs_socket, struct sched *s);
+void vss_init(int afs_socket, struct sched *s);
unsigned int vss_playing(void);
unsigned int vss_next(void);
unsigned int vss_repos(void);
git clone git://git.tuebingen.mpg.de/osl
-- [openssl](http://www.openssl.org/) or
+- [openssl](https://www.openssl.org/) or
[libgcrypt](ftp://ftp.gnupg.org/gcrypt/libgcrypt/). At least one
of these two libraries is needed as the backend for cryptographic
routines on both the server and the client side. Both openssl and
not necessary on the server side, i.e., for sending MP3 files.
- [libid3tag](http://www.underbit.com/products/mad/). For version-2
-ID3 tag support, you willl need the libid3tag development package
+ID3 tag support, you will need the libid3tag development package
`libid3tag0-dev`. Without libid3tag, only version-1 tags are
recognized. The mp3 tagger also needs this library for modifying
(id3v1 and id3v2) tags.
-- [ogg vorbis](http://www.xiph.org/downloads/). For ogg vorbis streams
+- [ogg vorbis](https://www.xiph.org/downloads/). For ogg vorbis streams
you need libogg, libvorbis, libvorbisfile. The corresponding Debian
packages are called `libogg-dev` and `libvorbis-dev`.
libfaad package. Install the faad library from sources (available
through the above link) to get the mp4ff library and header files.
-- [speex](http://www.speex.org/). In order to stream or decode speex
+- [speex](https://www.speex.org/). In order to stream or decode speex
files, libspeex (`libspeex-dev`) is required.
-- [flac](http://flac.sourceforge.net/). To stream or decode files
+- [flac](https://xiph.org/flac/). To stream or decode files
encoded with the _Free Lossless Audio Codec_, libFLAC (`libFLAC-dev`)
must be installed.
- [alsa-lib](ftp://ftp.alsa-project.org/pub/lib/). On Linux, you will
need to have the ALSA development package `libasound2-dev` installed.
-- [libao](http://downloads.xiph.org/releases/ao/). Needed to build
+- [libao](https://ftp.osuosl.org/pub/xiph/releases/ao/). Needed to build
the ao writer (ESD, PulseAudio,...). Debian package: `libao-dev`.
- [curses](ftp://ftp.gnu.org/pub/gnu/ncurses). Needed for
- UDP. Recommended for multicast LAN streaming.
-See the Appendix on [network protocols](/#Network.protocols)
+See the Appendix on [network protocols](#Network.protocols)
for brief descriptions of the various protocols relevant for network
audio streaming with paraslash.
the configure file which is shipped in the tarballs but has to be
generated when compiling from git.
-- [discount](http://www.pell.portland.or.us/~orc/Code/discount). The
+- [discount](http://www.pell.portland.or.us/~orc/Code/discount/). The
HTML version of this manual and some of the paraslash web pages are
written in the Markdown markup language and are translated into html
with the converter of the *Discount* package.
The preferred coding style for paraslash coincides more or less
with the style of the Linux kernel. So rather than repeating what is
-written [there](http://www.kernel.org/doc/Documentation/process/coding-style.rst),
+written [there](https://www.kernel.org/doc/Documentation/process/coding-style.rst),
here are the most important points.
- Burn the GNU coding standards.
---------------------
- [paraslash](http://people.tuebingen.mpg.de/maan/paraslash/)
-- [xmms](http://xmms2.org/wiki/Main_Page)
+- [xmms](https://xmms2.org/wiki/Main_Page)
- [mpg123](http://www.mpg123.de/)
-- [gstreamer](http://gstreamer.freedesktop.org/)
+- [gstreamer](https://gstreamer.freedesktop.org/)
- [icecast](http://www.icecast.org/)
-- [Audio Compress](http://beesbuzz.biz/code/audiocompress.php)
+- [Audio Compress](https://beesbuzz.biz/code/audiocompress.php)
External documentation
----------------------
- [The mathematics of
-Raid6](http://kernel.org/pub/linux/kernel/people/hpa/raid6.pdf)
+Raid6](https://www.kernel.org/pub/linux/kernel/people/hpa/raid6.pdf)
by H. Peter Anvin
- [Effective Erasure Codes for reliable Computer Communication
ret = convert_utf8_to_utf16(tags->artist, &artist);
if (ret < 0)
return ret;
+ assert(artist);
artist_bytes = ret;
ret = convert_utf8_to_utf16(tags->title, &title);
if (ret < 0)
goto out;
+ assert(title);
title_bytes = ret;
ret = convert_utf8_to_utf16(tags->comment, &comment);
if (ret < 0)
goto out;
+ assert(comment);
comment_bytes = ret;
if (cdo) {
ret = convert_utf8_to_utf16(tags->album, &album);
if (ret < 0)
return ret;
+ assert(album);
album_bytes = ret;
ret = convert_utf8_to_utf16(tags->year, &year);
if (ret < 0)
goto out;
+ assert(year);
year_bytes = ret;
result->size = 16 + 8 + 2; /* GUID, size, count */
/* name_length + name + null + data type + val length + val */
* This decoder handles Microsoft Windows Media Audio data version 2.
*/
-#define _XOPEN_SOURCE 600
-
#include <math.h>
#include <regex.h>
#include <sys/select.h>
struct vlc coef_vlc[2];
uint16_t *run_table[2];
uint16_t *level_table[2];
- const struct coef_vlc_table *coef_vlcs[2];
/** Frame length in samples. */
int frame_len;
/** log2 of frame_len. */
int block_len;
/** Current position in frame. */
int block_pos;
- /** True if mid/side stereo mode. */
- uint8_t ms_stereo;
/** True if channel is coded. */
uint8_t channel_coded[MAX_CHANNELS];
/** log2 ratio frame/exp. length. */
window[i] = sinf((i + 0.5) * (M_PI / (2.0 * n)));
}
-static void wmadec_cleanup(struct private_wmadec_data *pwd)
-{
- int i;
-
- for (i = 0; i < pwd->nb_block_sizes; i++)
- imdct_end(pwd->mdct_ctx[i]);
- if (pwd->ahi.use_exp_vlc)
- free_vlc(&pwd->exp_vlc);
- if (pwd->use_noise_coding)
- free_vlc(&pwd->hgain_vlc);
- for (i = 0; i < 2; i++) {
- free_vlc(&pwd->coef_vlc[i]);
- free(pwd->run_table[i]);
- free(pwd->level_table[i]);
- }
-}
-
-static void init_coef_vlc(struct vlc *vlc, uint16_t **prun_table,
- uint16_t **plevel_table, const struct coef_vlc_table *vlc_table)
+static void init_coef_vlc(struct private_wmadec_data *pwd, int sidx, int didx)
{
- int n = vlc_table->n;
- const uint8_t *table_bits = vlc_table->huffbits;
- const uint32_t *table_codes = vlc_table->huffcodes;
- const uint16_t *levels_table = vlc_table->levels;
- uint16_t *run_table, *level_table;
- int i, l, j, k, level;
+ const struct coef_vlc_table *src = coef_vlcs + sidx;
+ struct vlc *dst = pwd->coef_vlc + didx;
+ int i, l, j, k, level, n = src->n;
- init_vlc(vlc, VLCBITS, n, table_bits, table_codes, 4);
-
- run_table = para_malloc(n * sizeof(uint16_t));
- level_table = para_malloc(n * sizeof(uint16_t));
+ init_vlc(dst, VLCBITS, n, src->huffbits, src->huffcodes, 4);
+ pwd->run_table[didx] = para_malloc(n * sizeof(uint16_t));
+ pwd->level_table[didx] = para_malloc(n * sizeof(uint16_t));
i = 2;
level = 1;
k = 0;
while (i < n) {
- l = levels_table[k++];
+ l = src->levels[k++];
for (j = 0; j < l; j++) {
- run_table[i] = j;
- level_table[i] = level;
+ pwd->run_table[didx][i] = j;
+ pwd->level_table[didx][i] = level;
i++;
}
level++;
}
- *prun_table = run_table;
- *plevel_table = level_table;
}
/* compute the scale factor band sizes for each MDCT block size */
}
/* choose the VLC tables for the coefficients */
- coef_vlc_table = 2;
+ coef_vlc_table = 4;
if (ahi->sample_rate >= 32000) {
if (bps1 < 0.72)
coef_vlc_table = 0;
else if (bps1 < 1.16)
- coef_vlc_table = 1;
+ coef_vlc_table = 2;
}
- pwd->coef_vlcs[0] = &coef_vlcs[coef_vlc_table * 2];
- pwd->coef_vlcs[1] = &coef_vlcs[coef_vlc_table * 2 + 1];
- init_coef_vlc(&pwd->coef_vlc[0], &pwd->run_table[0], &pwd->level_table[0],
- pwd->coef_vlcs[0]);
- init_coef_vlc(&pwd->coef_vlc[1], &pwd->run_table[1], &pwd->level_table[1],
- pwd->coef_vlcs[1]);
+ init_coef_vlc(pwd, coef_vlc_table, 0);
+ init_coef_vlc(pwd, coef_vlc_table + 1, 1);
return 0;
}
last_exp = 36;
while (q < q_end) {
- code = get_vlc(&pwd->gb, pwd->exp_vlc.table, EXPVLCBITS);
+ code = get_vlc(&pwd->gb, &pwd->exp_vlc);
if (code < 0)
return code;
/* NOTE: this offset is the same as MPEG4 AAC ! */
if (val == (int)0x80000000)
val = get_bits(&pwd->gb, 7) - 19;
else {
- int code = get_vlc(&pwd->gb,
- pwd->hgain_vlc.table, HGAINVLCBITS);
+ int code = get_vlc(&pwd->gb, &pwd->hgain_vlc);
if (code < 0)
return code;
val += code - 18;
int ret, n, v, ch, code, bsize;
int coef_nb_bits, total_gain;
int nb_coefs[MAX_CHANNELS];
+ bool ms_stereo = false; /* mid/side stereo mode */
/* compute current block length */
if (pwd->ahi.use_variable_block_len) {
return -E_INCOHERENT_BLOCK_LEN;
if (pwd->ahi.channels == 2)
- pwd->ms_stereo = get_bit(&pwd->gb);
+ ms_stereo = get_bit(&pwd->gb);
v = 0;
for (ch = 0; ch < pwd->ahi.channels; ch++) {
int a = get_bit(&pwd->gb);
* special VLC tables are used for ms stereo because there is
* potentially less energy there
*/
- tindex = (ch == 1 && pwd->ms_stereo);
+ tindex = ch == 1 && ms_stereo;
coef_vlc = &pwd->coef_vlc[tindex];
run_table = pwd->run_table[tindex];
level_table = pwd->level_table[tindex];
eptr = ptr + nb_coefs[ch];
memset(ptr, 0, pwd->block_len * sizeof(int16_t));
for (;;) {
- code = get_vlc(&pwd->gb, coef_vlc->table, VLCBITS);
+ code = get_vlc(&pwd->gb, coef_vlc);
if (code < 0)
return code;
if (code == 1) /* EOB */
}
}
compute_mdct_coefficients(pwd, bsize, total_gain, nb_coefs);
- if (pwd->ms_stereo && pwd->channel_coded[1]) {
+ if (ms_stereo && pwd->channel_coded[1]) {
float a, b;
int i;
/*
n4 = pwd->block_len / 2;
if (pwd->channel_coded[ch])
imdct(pwd->mdct_ctx[bsize], pwd->output, pwd->coefs[ch]);
- else if (!(pwd->ms_stereo && ch == 1))
+ else if (!(ms_stereo && ch == 1))
memset(pwd->output, 0, sizeof(pwd->output));
/* multiply by the window and add in the frame */
return 0;
}
-static int wma_decode_superframe(struct private_wmadec_data *pwd, void *data,
- int *data_size, const uint8_t *buf, int buf_size)
+static int wma_decode_superframe(struct private_wmadec_data *pwd, void *out,
+ int *out_size, const uint8_t *in)
{
- int ret;
- int16_t *samples;
+ int ret, in_size = pwd->ahi.packet_size - WMA_FRAME_SKIP;
+ int16_t *samples = out;
- if (buf_size == 0) {
- pwd->last_superframe_len = 0;
- *data_size = 0;
- return 0;
- }
- if (buf_size < pwd->ahi.block_align) {
- *data_size = 0;
- return 0;
- }
- buf_size = pwd->ahi.block_align;
- samples = data;
- init_get_bits(&pwd->gb, buf, buf_size);
+ init_get_bits(&pwd->gb, in, in_size);
if (pwd->ahi.use_bit_reservoir) {
int i, nb_frames, bit_offset, pos, len;
uint8_t *q;
// PARA_DEBUG_LOG("have %d frames\n", nb_frames);
ret = -E_WMA_OUTPUT_SPACE;
if ((nb_frames + 1) * pwd->ahi.channels * pwd->frame_len
- * sizeof(int16_t) > *data_size)
+ * sizeof(int16_t) > *out_size)
goto fail;
bit_offset = get_bits(&pwd->gb, pwd->byte_offset_bits + 3);
/* read each frame starting from bit_offset */
pos = bit_offset + 4 + 4 + pwd->byte_offset_bits + 3;
- init_get_bits(&pwd->gb, buf + (pos >> 3),
+ init_get_bits(&pwd->gb, in + (pos >> 3),
(MAX_CODED_SUPERFRAME_SIZE - (pos >> 3)));
len = pos & 7;
if (len > 0)
((bit_offset + 4 + 4 + pwd->byte_offset_bits + 3) & ~7);
pwd->last_bitoffset = pos & 7;
pos >>= 3;
- len = buf_size - pos;
+ len = in_size - pos;
ret = -E_WMA_BAD_SUPERFRAME;
if (len > MAX_CODED_SUPERFRAME_SIZE || len < 0)
goto fail;
pwd->last_superframe_len = len;
- memcpy(pwd->last_superframe, buf + pos, len);
+ memcpy(pwd->last_superframe, in + pos, len);
} else {
PARA_DEBUG_LOG("not using bit reservoir\n");
ret = -E_WMA_OUTPUT_SPACE;
- if (pwd->ahi.channels * pwd->frame_len * sizeof(int16_t) > *data_size)
+ if (pwd->ahi.channels * pwd->frame_len * sizeof(int16_t) > *out_size)
goto fail;
/* single frame decode */
ret = wma_decode_frame(pwd, samples);
}
PARA_DEBUG_LOG("frame_len: %d, block_len: %d, outbytes: %d, eaten: %d\n",
pwd->frame_len, pwd->block_len,
- (int)((int8_t *)samples - (int8_t *)data), pwd->ahi.block_align);
- *data_size = (int8_t *)samples - (int8_t *)data;
+ (int)((int8_t *)samples - (int8_t *)out), pwd->ahi.block_align);
+ *out_size = (int8_t *)samples - (int8_t *)out;
return pwd->ahi.block_align;
fail:
/* reset the bit reservoir on errors */
static void wmadec_close(struct filter_node *fn)
{
struct private_wmadec_data *pwd = fn->private_data;
+ int i;
if (!pwd)
return;
- wmadec_cleanup(pwd);
+ for (i = 0; i < pwd->nb_block_sizes; i++)
+ imdct_end(pwd->mdct_ctx[i]);
+ if (pwd->ahi.use_exp_vlc)
+ free_vlc(&pwd->exp_vlc);
+ if (pwd->use_noise_coding)
+ free_vlc(&pwd->hgain_vlc);
+ for (i = 0; i < 2; i++) {
+ free_vlc(&pwd->coef_vlc[i]);
+ free(pwd->run_table[i]);
+ free(pwd->level_table[i]);
+ }
free(fn->private_data);
fn->private_data = NULL;
}
out_size = WMA_OUTPUT_BUFFER_SIZE;
out = para_malloc(out_size);
ret = wma_decode_superframe(pwd, out, &out_size,
- (uint8_t *)in + WMA_FRAME_SKIP, len - WMA_FRAME_SKIP);
+ (uint8_t *)in + WMA_FRAME_SKIP);
if (ret < 0) {
free(out);
goto err;