return buf;
}
-static char *read_tags(unsigned char *buf, size_t buflen)
+static void read_tags(unsigned char *buf, size_t buflen, struct afh_info *afhi)
{
unsigned char *p = buf;
- char *title = NULL, *artist = NULL, *album = NULL, *year = NULL,
- *comment = NULL, *result;
while (p + 32 < buf + buflen) {
unsigned char *q, type1[5], type2[5];
if (q + size2 > buf + buflen)
break;
if (!atom_cmp(type1, "©ART"))
- artist = get_tag(q, size2);
+ afhi->tags.artist = get_tag(q, size2);
else if (!atom_cmp(type1, "©alb"))
- album = get_tag(q, size2);
+ afhi->tags.album = get_tag(q, size2);
else if (!atom_cmp(type1, "©nam"))
- title = get_tag(q, size2);
+ afhi->tags.title = get_tag(q, size2);
else if (!atom_cmp(type1, "©cmt"))
- comment = get_tag(q, size2);
+ afhi->tags.comment = get_tag(q, size2);
else if (!atom_cmp(type1, "©day"))
- year = get_tag(q, size2);
+ afhi->tags.year = get_tag(q, size2);
p += size1;
}
- result = make_taginfo(title, artist, album, year, comment);
- free(title);
- free(artist);
- free(album);
- free(year);
- free(comment);
- return result;
}
-static char *read_meta(unsigned char *buf, size_t buflen)
+static void read_meta(unsigned char *buf, size_t buflen, struct afh_info *afhi)
{
unsigned char *p = buf;
continue;
}
p += 4;
- return read_tags(p, buflen - (p - buf));
+ return read_tags(p, buflen - (p - buf), afhi);
}
- return make_taginfo(NULL, NULL, NULL, NULL, NULL);
}
-static char *aac_get_taginfo(unsigned char *buf, size_t buflen)
+static void aac_get_taginfo(unsigned char *buf, size_t buflen,
+ struct afh_info *afhi)
{
int i;
uint64_t subsize;
p = buf + i;
i += read_atom_header(p, &subsize, type);
p = buf + i;
- return read_meta(p, buflen - i);
+ return read_meta(p, buflen - i, afhi);
}
PARA_INFO_LOG("no meta data\n");
- return make_taginfo(NULL, NULL, NULL, NULL, NULL);
}
static ssize_t aac_compute_chunk_table(struct afh_info *afhi,
mp4AudioSpecificConfig mp4ASC;
NeAACDecHandle handle = NULL;
unsigned char *umap = (unsigned char *) map;
- char *taginfo;
ret = aac_find_esds(umap, numbytes, &skip, &decoder_len);
if (ret < 0)
goto out;
- taginfo = aac_get_taginfo(umap, numbytes);
+ aac_get_taginfo(umap, numbytes, afhi);
handle = aac_open();
ret = -E_AAC_AFH_INIT;
if (NeAACDecInit(handle, umap + skip, decoder_len, &rate, &channels))
ret = (afhi->chunk_table[afhi->chunks_total] - afhi->chunk_table[0]) * 8; /* bits */
ret += (channels * afhi->seconds_total * 500); /* avoid rounding error */
afhi->bitrate = ret / (channels * afhi->seconds_total * 1000);
- afhi->info_string = make_message("%s:\n%s",
- status_item_list[SI_AUDIO_FILE_INFO],
- taginfo);
- free(taginfo);
- tv_scale(20, &afhi->chunk_tv, &afhi->eof_tv);
ret = 1;
out:
if (handle)
"%s: %dHz\n" /* frequency */
"%s: %d\n" /* channels */
"%s: %lu\n" /* seconds total */
- "%s" /* tag info */
"%s: %lu: %lu\n" /* chunk time */
- "%s: %lu\n", /* num chunks */
+ "%s: %lu\n" /* num chunks */
+ "%s: %s\n" /* techinfo */
+ "%s: %s\n" /* artist */
+ "%s: %s\n" /* title */
+ "%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,
- afhi->info_string,
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_NUM_CHUNKS], afhi->chunks_total,
+ 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 : ""
);
}
print_info(audio_format_num, &afhi);
if (conf.chunk_table_given)
print_chunk_table(&afhi);
+ free(afhi.techinfo);
+ free(afhi.tags.artist);
+ free(afhi.tags.title);
+ free(afhi.tags.year);
+ free(afhi.tags.album);
+ free(afhi.tags.comment);
+ free(afhi.chunk_table);
printf("\n");
}
ret2 = para_munmap(audio_file_data, audio_file_size);
/** \endcond */
+/**
+ * The tags used by all audio format handlers.
+ *
+ * Paraslash only uses the more common tags. These are recognized
+ * for all supported audio formats.
+ */
+struct taginfo {
+ /** TPE1 (id3v2) / ARTIST (vorbis) / ©ART (aac) */
+ char *artist;
+ /** TIT2/TITLE/©nam */
+ char *title;
+ /** TDRC/YEAR/©day */
+ char *year;
+ /** TALB/ALBUM/©alb */
+ char *album;
+ /** COMM/COMMENT/©cmt */
+ char *comment;
+};
+
/** Audio format dependent information. */
struct afh_info {
/** The number of chunks this audio file contains. */
long unsigned chunks_total;
/** The length of the audio file in seconds. */
long unsigned seconds_total;
- /** A string that gets filled in by the audio format handler. */
- char *info_string;
+ /** Audio handler specific info about the file. */
+ char *techinfo;
+ /** Id3 tags, vorbis comments, aac tags. */
+ struct taginfo tags;
/**
* The table that specifies the offset of the individual pieces in
* the current audio file.
uint32_t *chunk_table;
/** Period of time between sending data chunks. */
struct timeval chunk_tv;
- /** End of file timeout - Do not load new audio file until this time. */
- struct timeval eof_tv;
/**
* The position of the header within the audio file. Ignored if \a
* header_len equals zero.
void *map, const char **buf, size_t *len);
uint32_t afh_get_largest_chunk_size(struct afh_info *afhi);
void afh_get_header(struct afh_info *afhi, void *map, const char **buf, size_t *len);
-char *make_taginfo(char *title, char *artist, char *album, char *year,
- char *comment);
return -E_AUDIO_FORMAT;
}
-/**
- * Pretty-print the given meta-info.
- *
- * \param title The title of the audio file.
- * \param artist The artist.
- * \param album The name of the album.
- * \param year Year of release.
- * \param comment Further comments.
- *
- * This function is called by each audio format handler to produce the tag info
- * status items. Usually, the audio format handlers read this info from the
- * audio file (id3 tags, vorbis comments, ...).
- *
- * It is OK to pass \p NULL pointers for any argument in which case a suitable
- * string is inserted which indicates that this information is not available.
- *
- * \return The status item string. It must be freed by the caller.
- */
-char *make_taginfo(char *title, char *artist, char *album, char *year,
- char *comment)
-{
- return make_message("%s: %s, by %s\n" /* taginfo1 */
- "%s: A: %s, Y: %s, C: %s\n", /* taginfo2 */
- status_item_list[SI_TAGINFO1],
- (title && *title)? title : "(title tag not set)",
- (artist && *artist)? artist : "(artist tag not set)",
- status_item_list[SI_TAGINFO2],
- (album && *album)? album : "(album tag not set)",
- (year && *year)? year : "????",
- (comment && *comment)? comment : "(comment tag not set)"
- );
-}
-
/**
* Call get_file_info() to obtain an afhi structure.
*
afhi->header_offset = 0;
afhi->header_len = 0;
+ afhi->techinfo = NULL;
+ afhi->tags.artist = NULL;
+ afhi->tags.title = NULL;
+ afhi->tags.year = NULL;
+ afhi->tags.album = NULL;
+ afhi->tags.comment = NULL;
format = guess_audio_format(path);
if (format >= 0) {
ret = afl[format].get_file_info(data, size, fd, afhi);
- if (ret >= 0)
- return format;
+ if (ret >= 0) {
+ ret = format;
+ goto success;
+ }
}
FOR_EACH_AUDIO_FORMAT(i) {
if (i == format) /* we already tried this one to no avail */
continue;
ret = afl[i].get_file_info(data, size, fd, afhi);
- if (ret >= 0)
- return i;
+ if (ret >= 0) {
+ ret = i;
+ goto success;
+ }
PARA_WARNING_LOG("%s\n", para_strerror(-ret));
}
return -E_AUDIO_FORMAT;
+success:
+ if (!afhi->techinfo)
+ afhi->techinfo = para_strdup(NULL);
+ if (!afhi->tags.artist)
+ afhi->tags.artist = para_strdup(NULL);
+ if (!afhi->tags.title)
+ afhi->tags.title = para_strdup(NULL);
+ if (!afhi->tags.year)
+ afhi->tags.year = para_strdup(NULL);
+ if (!afhi->tags.album)
+ afhi->tags.album = para_strdup(NULL);
+ if (!afhi->tags.comment)
+ afhi->tags.comment = para_strdup(NULL);
+ PARA_DEBUG_LOG("techinfo: %s\n", afhi->techinfo);
+ PARA_DEBUG_LOG("artist: %s\n", afhi->tags.artist);
+ PARA_DEBUG_LOG("title: %s\n", afhi->tags.title);
+ PARA_DEBUG_LOG("year: %s\n", afhi->tags.year);
+ PARA_DEBUG_LOG("album: %s\n", afhi->tags.album);
+ PARA_DEBUG_LOG("comment: %s\n", afhi->tags.comment);
+ return ret;
}
/**
*
* This function sets \a buf to \p NULL and \a len to zero if \a map or \a
* afhi is \p NULL, or if the current audio format does not need special
- * header treamtment.
+ * header treatment.
*/
void afh_get_header(struct afh_info *afhi, void *map, const char **buf, size_t *len)
{
CHUNK_TV_TV_USEC_OFFSET = 36,
/** Number of channels is stored here. (1 byte) */
AFHI_CHANNELS_OFFSET = 40,
- /** EOF timeout in ms. (2 byte) */
- AFHI_EOF_OFFSET = 41,
/** The tag info position. */
- AFHI_INFO_STRING_OFFSET = 43,
+ AFHI_INFO_STRING_OFFSET = 41,
/** Minimal on-disk size of a valid afhi struct. */
- MIN_AFHI_SIZE = 44
+ MIN_AFHI_SIZE = 47, /* at least 6 null bytes for techinfo/tags */
};
static unsigned sizeof_afhi_buf(const struct afh_info *afhi)
{
if (!afhi)
return 0;
- return strlen(afhi->info_string) + MIN_AFHI_SIZE;
+ return MIN_AFHI_SIZE
+ + strlen(afhi->techinfo)
+ + strlen(afhi->tags.artist)
+ + strlen(afhi->tags.title)
+ + strlen(afhi->tags.year)
+ + strlen(afhi->tags.album)
+ + strlen(afhi->tags.comment);
}
static void save_afhi(struct afh_info *afhi, char *buf)
{
+ char *p;
+
if (!afhi)
return;
write_u32(buf + AFHI_SECONDS_TOTAL_OFFSET, afhi->seconds_total);
write_u32(buf + HEADER_OFFSET_OFFSET, afhi->header_offset);
write_u32(buf + CHUNK_TV_TV_SEC_OFFSET, afhi->chunk_tv.tv_sec);
write_u32(buf + CHUNK_TV_TV_USEC_OFFSET, afhi->chunk_tv.tv_usec);
- write_u16(buf + AFHI_EOF_OFFSET, tv2ms(&afhi->eof_tv));
- strcpy(buf + AFHI_INFO_STRING_OFFSET, afhi->info_string); /* OK */
+ p = buf + AFHI_INFO_STRING_OFFSET;
+ /* The sprintf's below are OK as our caller made sure that buf is large enough */
+ p += sprintf(p, "%s", afhi->techinfo) + 1;
+ p += sprintf(p, "%s", afhi->tags.artist) + 1;
+ p += sprintf(p, "%s", afhi->tags.title) + 1;
+ p += sprintf(p, "%s", afhi->tags.year) + 1;
+ p += sprintf(p, "%s", afhi->tags.album) + 1;
+ sprintf(p, "%s", afhi->tags.comment);
}
static void load_afhi(const char *buf, struct afh_info *afhi)
afhi->header_offset = read_u32(buf + HEADER_OFFSET_OFFSET);
afhi->chunk_tv.tv_sec = read_u32(buf + CHUNK_TV_TV_SEC_OFFSET);
afhi->chunk_tv.tv_usec = read_u32(buf + CHUNK_TV_TV_USEC_OFFSET);
- ms2tv(read_u16(buf + AFHI_EOF_OFFSET), &afhi->eof_tv);
- afhi->info_string = para_strdup(buf + AFHI_INFO_STRING_OFFSET);
+ afhi->techinfo = buf + AFHI_INFO_STRING_OFFSET;
+ afhi->tags.artist = afhi->techinfo + strlen(afhi->techinfo) + 1;
+ afhi->tags.title = afhi->tags.artist + strlen(afhi->tags.artist) + 1;
+ afhi->tags.year = afhi->tags.title + strlen(afhi->tags.title) + 1;
+ afhi->tags.album = afhi->tags.year + strlen(afhi->tags.year) + 1;
+ afhi->tags.comment = afhi->tags.album + strlen(afhi->tags.album) + 1;
}
static unsigned sizeof_chunk_table(struct afh_info *afhi)
* Get the row of the audio file table corresponding to the given hash value.
*
* \param hash The hash value of the desired audio file.
- * \param row resul pointer.
+ * \param row Result pointer.
*
* \return Standard.
*/
"%s: %lu\n" /* seconds total */
"%s: %s\n" /* last played time */
"%s: %d\n" /* num_played */
- "%s: %u\n" /* ampplification */
- "%s" /* tag info */
+ "%s: %u\n" /* amplification */
"%s: %lu\n" /* chunk time */
- "%s: %lu\n", /* num chunks */
+ "%s: %lu\n" /* num chunks */
+ "%s: %s\n" /* techinfo */
+ "%s: %s\n" /* artist */
+ "%s: %s\n" /* title */
+ "%s: %s\n" /* year */
+ "%s: %s\n" /* album */
+ "%s: %s\n", /* comment */
filename_lines,
have_score? status_item_list[SI_SCORE] : "",
have_score? ": " : "",
status_item_list[SI_LAST_PLAYED], last_played_time,
status_item_list[SI_NUM_PLAYED], afsi->num_played,
status_item_list[SI_AMPLIFICATION], afsi->amp,
- afhi->info_string,
status_item_list[SI_CHUNK_TIME], tv2ms(&afhi->chunk_tv),
- status_item_list[SI_NUM_CHUNKS], afhi->chunks_total
+ status_item_list[SI_NUM_CHUNKS], afhi->chunks_total,
+ status_item_list[SI_TECHINFO], afhi->techinfo,
+ status_item_list[SI_ARTIST], afhi->tags.artist,
+ status_item_list[SI_TITLE], afhi->tags.title,
+ status_item_list[SI_YEAR], afhi->tags.year,
+ status_item_list[SI_ALBUM], afhi->tags.album,
+ status_item_list[SI_COMMENT], afhi->tags.comment
);
if (ret < 0)
goto out;
free(image_lines);
free(filename_lines);
out:
- free(afhi->info_string);
return ret;
}
"%s: \n" /* seconds total */
"%s: \n" /* num played */
"%s: \n" /* last played */
- "%s: \n" /* audio file info */
- "%s: \n" /* taginfo1 */
- "%s: \n" /* taginfo2 */
+ "%s: \n" /* techinfo */
+ "%s: \n" /* artist */
+ "%s: \n" /* title */
+ "%s: \n" /* year */
+ "%s: \n" /* album */
+ "%s: \n" /* comment */
"%s: \n" /* amplification */
,
status_item_list[SI_PATH],
status_item_list[SI_SECONDS_TOTAL],
status_item_list[SI_NUM_PLAYED],
status_item_list[SI_LAST_PLAYED],
- status_item_list[SI_AUDIO_FILE_INFO],
- status_item_list[SI_TAGINFO1],
- status_item_list[SI_TAGINFO2],
+ status_item_list[SI_TECHINFO],
+ status_item_list[SI_ARTIST],
+ status_item_list[SI_TITLE],
+ status_item_list[SI_YEAR],
+ status_item_list[SI_ALBUM],
+ status_item_list[SI_COMMENT],
status_item_list[SI_AMPLIFICATION]
);
}
-static void fixup_taginfo(char *begin, char *end)
-{
- char *p = begin;
-
- for (;;) {
- p = strchr(p, '\n');
- if (!p)
- break;
- if (p >= end - 1)
- break;
- *p = ' ';
- p++;
- }
-}
-
-/* crap, remove this ASAP. */
-static int fixup_info_string(char *info_string)
-{
- char *t1, *t2, *end;
-
- if (strncmp(info_string, "audio_file_info:", 16))
- return -ERRNO_TO_PARA_ERROR(EINVAL);
- t1 = strstr(info_string, "\ntaginfo1:");
- if (!t1)
- return -ERRNO_TO_PARA_ERROR(EINVAL);
- t2 = strstr(info_string, "\ntaginfo2: ");
- if (!t2)
- return -ERRNO_TO_PARA_ERROR(EINVAL);
-
- end = t2 + strlen(t2) + 1;
- fixup_taginfo(info_string + 16, t1);
- fixup_taginfo(t1 + 10, t2);
- fixup_taginfo(t2 + 10, end);
-
- if (t1 - info_string < 80 && t2 - t1 < 80 && end - t2 < 80)
- return 0;
- if (t1 - info_string >= 80) {
- memmove(info_string + 80, t1, end - t1);
- t1 = info_string + 80;
- t2 -= t1 - info_string - 80;
- end -= t1 - info_string - 80;
- }
- if (t2 - t1 >= 80) {
- memmove(t1 + 80, t2, end - t2);
- end -= t2 - t1 - 80;
- t2 = t1 + 80;
- }
- if (end - t2 >= 80) {
- t2[78] = '\n';
- t2[79] = '\0';
- }
- return 1;
-}
-
static int make_status_items(struct audio_file_data *afd,
struct afs_info *afsi, char *path, long score,
HASH_TYPE *hash)
time_t current_time;
int ret;
- ret = fixup_info_string(afd->afhi.info_string);
- if (ret < 0) {
- PARA_WARNING_LOG("ignoring invalid tag info\n");
- afd->afhi.info_string[0] = '\0';
- } else if (ret)
- PARA_NOTICE_LOG("truncated overlong tag info\n");
time(¤t_time);
- ret = print_list_item(&d, &opts, &pb, current_time); /* frees info string */
- afd->afhi.info_string = NULL;
+ ret = print_list_item(&d, &opts, &pb, current_time);
if (ret < 0)
goto out;
strncpy(afd->verbose_ls_output, pb.buf, VERBOSE_LS_OUTPUT_SIZE);
ret = save_afd(afd);
err:
free(afd->afhi.chunk_table);
- free(afd->afhi.info_string);
osl_close_disk_object(&chunk_table_obj);
return ret;
}
}
return 1;
err:
- free(d->afhi.info_string);
return ret;
}
free(obj.data);
if (afhi_ptr) {
free(afhi_ptr->chunk_table);
- free(afhi_ptr->info_string);
+ free(afhi_ptr->techinfo);
+ free(afhi_ptr->tags.artist);
+ free(afhi_ptr->tags.title);
+ free(afhi_ptr->tags.year);
+ free(afhi_ptr->tags.album);
+ free(afhi_ptr->tags.comment);
}
/* Stop adding files only on send errors. */
return send_ret;
################################################################## status items
status_items="basename status num_played mtime bitrate frequency file_size
-status_flags format score audio_file_info taginfo1 taginfo2 afs_mode
+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"
+last_played num_chunks chunk_time amplification artist title year album
+comment"
# $1: prefix, $2: items
AC_DEFUN([make_enum_items], [$(
d[SI_AMPLIFICATION].y = 27;
d[SI_AMPLIFICATION].len = 8;
- d[SI_AUDIO_FILE_INFO].prefix = "";
- d[SI_AUDIO_FILE_INFO].postfix = "";
- d[SI_AUDIO_FILE_INFO].fg = COLOR_GREEN;
- d[SI_AUDIO_FILE_INFO].bg = COLOR_BLACK;
- d[SI_AUDIO_FILE_INFO].align = CENTER;
- d[SI_AUDIO_FILE_INFO].x = 0;
- d[SI_AUDIO_FILE_INFO].y = 43;
- d[SI_AUDIO_FILE_INFO].len = 100;
-
- d[SI_TAGINFO1].prefix = "";
- d[SI_TAGINFO1].postfix = "";
- d[SI_TAGINFO1].fg = COLOR_GREEN;
- d[SI_TAGINFO1].bg = COLOR_BLACK;
- d[SI_TAGINFO1].align = CENTER;
- d[SI_TAGINFO1].x = 0;
- d[SI_TAGINFO1].y = 53;
- d[SI_TAGINFO1].len = 100;
-
- d[SI_TAGINFO2].prefix = "";
- d[SI_TAGINFO2].postfix = "";
- d[SI_TAGINFO2].fg = COLOR_GREEN;
- d[SI_TAGINFO2].bg = COLOR_BLACK;
- d[SI_TAGINFO2].align = CENTER;
- d[SI_TAGINFO2].x = 0;
- d[SI_TAGINFO2].y = 63;
- d[SI_TAGINFO2].len = 100;
+ d[SI_TECHINFO].prefix = "";
+ d[SI_TECHINFO].postfix = "";
+ d[SI_TECHINFO].fg = COLOR_GREEN;
+ d[SI_TECHINFO].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].fg = COLOR_GREEN;
+ d[SI_TITLE].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].fg = COLOR_GREEN;
+ d[SI_ARTIST].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].fg = COLOR_GREEN;
+ d[SI_YEAR].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].fg = COLOR_GREEN;
+ d[SI_ALBUM].bg = COLOR_BLACK;
+ d[SI_ALBUM].align = CENTER;
+ 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].fg = COLOR_GREEN;
+ d[SI_COMMENT].bg = COLOR_BLACK;
+ d[SI_COMMENT].align = CENTER;
+ 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 = "";
ret = get_afhi_of_row(row, &afhi);
if (ret< 0)
return ret;
- free(afhi.info_string); /* don't need the tag info */
ret = get_audio_file_path_of_row(row, &path);
if (ret< 0)
return ret;
return NULL;
}
-static char *mp3_get_id3(__a_unused unsigned char *map,
- __a_unused size_t numbytes, int fd)
+static void mp3_get_id3(__a_unused unsigned char *map,
+ __a_unused size_t numbytes, int fd, struct taginfo *tags)
{
int i;
struct id3_tag *id3_t;
- char *title = NULL, *artist = NULL, *album = NULL, *year = NULL,
- *comment = NULL, *result;
struct id3_file *id3_f = id3_file_fdopen(fd, ID3_FILE_MODE_READONLY);
if (!id3_f)
- goto no_tag;
+ return;
id3_t = id3_file_tag(id3_f);
- if (!id3_t)
- goto no_tag;
+ if (!id3_t) {
+ id3_file_close(id3_f);
+ return;
+ }
for (i = 0; i < id3_t->nframes; i++) {
struct id3_frame *fr = id3_t->frames[i];
if (!strcmp(fr->id, "TIT2")) {
- if (!title)
- title = get_strings(fr);
+ if (!tags->title)
+ tags->title = get_strings(fr);
continue;
}
if (!strcmp(fr->id, "TPE1")) {
- if (!artist)
- artist = get_strings(fr);
+ if (!tags->artist)
+ tags->artist = get_strings(fr);
continue;
}
if (!strcmp(fr->id, "TALB")) {
- if (!album)
- album = get_strings(fr);
+ if (!tags->album)
+ tags->album = get_strings(fr);
continue;
}
if (!strcmp(fr->id, "TDRC")) {
- if (!year)
- year = get_strings(fr);
+ if (!tags->year)
+ tags->year = get_strings(fr);
continue;
}
if (!strcmp(fr->id, "COMM")) {
- if (!comment)
- comment = get_strings(fr);
+ if (!tags->comment)
+ tags->comment = get_strings(fr);
continue;
}
}
id3_file_close(id3_f);
- result = make_taginfo(title, artist, album, year, comment);
- free(title);
- free(artist);
- free(album);
- free(year);
- free(comment);
- return result;
-no_tag:
- if (id3_f)
- id3_file_close(id3_f);
- return make_message("%s: (no id3 v1/v2 tag)\n%s:\n",
- status_item_list[SI_TAGINFO1],
- status_item_list[SI_TAGINFO2]);
}
#else /* HAVE_LIBID3TAG */
return string;
}
-static char *mp3_get_id3(unsigned char *map, size_t numbytes, __a_unused int fd)
+static void mp3_get_id3(unsigned char *map, size_t numbytes, __a_unused int fd,
+ struct taginfo *tags)
{
char title[31], artist[31], album[31], year[5], comment[31];
off_t fpos;
if (numbytes < 128 || strncmp("TAG", (char *)map + numbytes - 128, 3)) {
PARA_DEBUG_LOG("no id3 v1 tag\n");
- return make_message("%s: (no id3 v1 tag)\n%s:\n",
- status_item_list[SI_TAGINFO1],
- status_item_list[SI_TAGINFO2]);
+ return;
}
fpos = numbytes - 125;
memcpy(title, map + fpos, 30);
unpad(album);
unpad(year);
unpad(comment);
- return make_taginfo(title, artist, album, year, comment);
+ tags->artist = para_strdup(artist);
+ tags->title = para_strdup(title);
+ tags->year = para_strdup(year);
+ tags->album = para_strdup(album);
+ tags->comment = para_strdup(comment);
}
#endif /* HAVE_LIBID3TAG */
unsigned chunk_table_size = 1000; /* gets increased on demand */
off_t fpos = 0;
struct mp3header header;
- char *taginfo;
afhi->chunks_total = 0;
afhi->chunk_table = para_malloc(chunk_table_size * sizeof(uint32_t));
- taginfo = mp3_get_id3(map, numbytes, fd);
while (1) {
int freq, br;
struct timeval tmp, cct; /* current chunk time */
tv_divide(afhi->chunks_total, &total_time, &afhi->chunk_tv);
PARA_DEBUG_LOG("%lu chunks, each %lums\n", afhi->chunks_total,
tv2ms(&afhi->chunk_tv));
- tv_scale(3, &afhi->chunk_tv, &afhi->eof_tv);
- PARA_DEBUG_LOG("eof timeout: %lu\n", tv2ms(&afhi->eof_tv));
- afhi->info_string = make_message("%s: %cbr, %s\n%s",
- status_item_list[SI_AUDIO_FILE_INFO], vbr? 'v' : 'c',
- header_mode(&header), taginfo);
- free(taginfo);
+ afhi->techinfo = make_message("%cbr, %s", vbr? 'v' : 'c',
+ header_mode(&header));
+ mp3_get_id3(map, numbytes, fd, &afhi->tags);
return 1;
err_out:
- free(taginfo);
PARA_ERROR_LOG("%s\n", para_strerror(-ret));
free(afhi->chunk_table);
return ret;
return num_chunks;
}
-static void ogg_write_info_string(OggVorbis_File *vf, struct afh_info *afhi)
+static void ogg_get_vorbis_comments(OggVorbis_File *vf, struct afh_info *afhi)
{
- char *taginfo;
vorbis_comment *vc = ov_comment(vf,-1);
- if (vc) {
- char *artist, *title, *album, *year, *comment;
- artist = vorbis_comment_query(vc, "artist", 0);
- title = vorbis_comment_query(vc, "title", 0);
- album = vorbis_comment_query(vc, "album", 0);
- year = vorbis_comment_query(vc, "year", 0);
- comment = vorbis_comment_query(vc, "comment", 0);
- taginfo = make_taginfo(title, artist, album, year, comment);
- } else
- taginfo = make_message("%s: (no vorbis comments found)\n%s:\n",
- status_item_list[SI_TAGINFO1],
- status_item_list[SI_TAGINFO2]);
- afhi->info_string = make_message("%s:\n%s",
- status_item_list[SI_AUDIO_FILE_INFO], taginfo);
- free(taginfo);
+ if (!vc)
+ return;
+ afhi->tags.artist = para_strdup(vorbis_comment_query(vc, "artist", 0));
+ afhi->tags.title = para_strdup(vorbis_comment_query(vc, "title", 0));
+ afhi->tags.album = para_strdup(vorbis_comment_query(vc, "album", 0));
+ afhi->tags.year = para_strdup(vorbis_comment_query(vc, "year", 0));
+ afhi->tags.comment = para_strdup(vorbis_comment_query(vc, "comment", 0));
}
/*
afhi->chunks_total = ogg_compute_chunk_table(&of, afhi, afhi->seconds_total);
afhi->chunk_tv.tv_sec = 0;
afhi->chunk_tv.tv_usec = 250 * 1000;
- tv_scale(10 / afhi->channels, &afhi->chunk_tv, &afhi->eof_tv);
- ogg_write_info_string(&of, afhi);
+ ogg_get_vorbis_comments(&of, afhi);
ret = 1;
err:
ov_clear(&of); /* keeps the file open */
*
*
* - The main programs: \ref server.c, \ref audiod.c, \ref client.c,
- * \ref audioc.c, \ref fsck.c, \ref afh.c
+ * \ref audioc.c, \ref afh.c
* - Server: \ref server_command, \ref sender,
* - Audio file selector: \ref audio_format_handler, \ref mood, \ref afs_table,
* - Client: \ref receiver, \ref receiver_node, \ref filter, \ref filter_node.
* - Time: \ref time.c,
* - Spawning processes: \ref exec.c,
* - Inter process communication: \ref ipc.c,
- * - The object storage layer: \ref osl.c,
* - Blob tables: \ref blob.c,
* - The error subssystem: \ref error.h.
* - Access control for paraslash senders: \ref acl.c, \ref acl.h.
* Low-level data structures:
*
* - Doubly linked lists: \ref list.h,
- * - Red-black trees: \ref rbtree.h, \ref rbtree.c,
* - Ring buffer: \ref ringbuffer.c, \ref ringbuffer.h,
* - Hashing: \ref hash.h, \ref sha1.h, \ref sha1.c,
* - Crypto: \ref crypt.c.
waitpid(mmd->afs_pid, NULL, 0);
cleanup:
free(mmd->afd.afhi.chunk_table);
- free(mmd->afd.afhi.info_string);
close_listed_fds();
mutex_destroy(mmd_mutex);
shm_detach(mmd);
char *peer_name;
pid_t child_pid;
uint32_t *chunk_table;
- char *info_string;
if (!FD_ISSET(sct->listen_fd, &s->rfds))
return;
mmd->num_connects++;
mmd->active_connections++;
random();
- /* The chunk table and the info_string are pointers located in the
- * mmd struct that point to dynamically allocated memory that must be
- * freed by the parent and the child. However, as the mmd struct is in
- * a shared memory area, there's no guarantee that after the fork these
- * pointers are still valid in child context. As these two pointers are
- * not used in the child anyway, we save them to local variables and
- * free the memory via that copy in the child.
+ /*
+ * The chunk table is a pointer located in the mmd struct that point to
+ * dynamically allocated memory that must be freed by the parent and
+ * the child. However, as the mmd struct is in a shared memory area,
+ * there's no guarantee that after the fork these pointers are still
+ * valid in child context. As this pointer is not used in the child
+ * anyway, we save it to a local variable and free the memory via that
+ * copy in the child.
*/
- info_string = mmd->afd.afhi.info_string;
chunk_table = mmd->afd.afhi.chunk_table;
child_pid = fork();
if (child_pid < 0) {
return;
}
/* mmd might already have changed at this point */
- free(info_string);
free(chunk_table);
alarm(ALARM_TIMEOUT);
close_listed_fds();
static void set_eof_barrier(struct vss_task *vsst)
{
struct fec_client *fc;
- struct timeval timeout = mmd->afd.afhi.eof_tv,
- *chunk_tv = vss_chunk_time();
+ struct timeval timeout = {1, 0}, *chunk_tv = vss_chunk_time();
if (!chunk_tv)
goto out;
mmd->afd.afhi.chunk_tv.tv_usec = 0;
free(mmd->afd.afhi.chunk_table);
mmd->afd.afhi.chunk_table = NULL;
- free(mmd->afd.afhi.info_string);
- mmd->afd.afhi.info_string = make_message("%s:\n%s:\n%s:\n", status_item_list[SI_AUDIO_FILE_INFO],
- status_item_list[SI_TAGINFO1], status_item_list[SI_TAGINFO2]);
make_empty_status_items(mmd->afd.verbose_ls_output);
mmd->mtime = 0;
mmd->size = 0;
if (passed_fd < 0)
goto err;
shmid = afs_data;
- free(mmd->afd.afhi.info_string);
ret = load_afd(shmid, &mmd->afd);
if (ret < 0)
goto err;