/** \file afs.c audio file sending functions
*
- * This contains the audio sending part of para_server which is independent
- * of the current audio format, database tool and of the activated senders.
+ * This contains the audio sending part of para_server which is independent of
+ * the current audio format, audio file selector and of the activated senders.
*/
+#include "server.h"
#include <sys/time.h> /* gettimeofday */
#include "server.cmdline.h"
#include "db.h"
-#include "server.h"
+#include "afh.h"
#include "afs.h"
#include "send.h"
#include "error.h"
static struct timeval eof_barrier;
extern struct misc_meta_data *mmd;
-extern struct dbtool dblist[];
+extern struct audio_file_selector selectors[];
extern struct sender senders[];
extern struct gengetopt_args_info conf;
static FILE *audio_file = NULL;
#if 1
- void mp3_init(void *);
+ void mp3_init(struct audio_format_handler *);
#endif
#ifdef HAVE_OGGVORBIS
- void ogg_init(void *);
+ void ogg_init(struct audio_format_handler *);
+#endif
+#ifdef HAVE_FAAD
+ void aac_afh_init(struct audio_format_handler *);
#endif
/**
* the list of supported audio formats
*/
-struct audio_format afl[] = {
+static struct audio_format_handler afl[] = {
#if 1
{
.name = "mp3",
.name = "ogg",
.init = ogg_init,
},
+#endif
+#ifdef HAVE_FAAD
+ {
+ .name = "aac",
+ .init = aac_afh_init,
+ },
#endif
{
.name = NULL,
}
};
-
+#define FOR_EACH_AUDIO_FORMAT(i) for (i = 0; afl[i].name; i++)
/**
* check if audio file sender is playing
afl[i].init(&afl[i]);
}
ms2tv(conf.announce_time_arg, &announce_tv);
- PARA_INFO_LOG("announce timeval: %lu:%lu\n", announce_tv.tv_sec, announce_tv.tv_usec);
+ PARA_INFO_LOG("announce timeval: %lums\n", tv2ms(&announce_tv));
for (i = 0; senders[i].name; i++) {
PARA_NOTICE_LOG("initializing %s sender\n", senders[i].name);
senders[i].init(&senders[i]);
&mmd->chunks_total, &mmd->seconds_total);
}
-/*
+/**
* guess the audio format judging from filename
+ *
* \param name the filename
*
* \return This function returns -1 if it has no idea what kind of audio
* file this might be. Otherwise the (non-negative) number of the audio format
* is returned.
*/
-static int guess_audio_format(const char *name)
+int guess_audio_format(const char *name)
{
-
- int i, len1 = strlen(name), len2;
-
- for (i = 0; afl[i].name; i++) {
- len2 = strlen(afl[i].name);
- if (len1 < len2)
- continue;
- if (!strncasecmp(name + (len1 - len2), afl[i].name, len2)) {
- PARA_DEBUG_LOG("might be %s\n", afl[i].name);
+ int i,j, len = strlen(name);
+
+ FOR_EACH_AUDIO_FORMAT(i) {
+ for (j = 0; afl[i].suffixes[j]; j++) {
+ const char *p = afl[i].suffixes[j];
+ int plen = strlen(p);
+ if (len < plen + 1)
+ continue;
+ if (name[len - plen - 1] != '.')
+ continue;
+ if (strcasecmp(name + len - plen, p))
+ continue;
+ PARA_DEBUG_LOG("might be %s\n", audio_format_name(i));
return i;
}
}
{
int i;
- for (i = 0; afl[i].name; i++) {
+ FOR_EACH_AUDIO_FORMAT(i) {
if (i == omit || !afl[i].get_file_info)
continue;
rewind(audio_file);
static void get_song(void)
{
- char **sl = dblist[mmd->dbt_num].get_audio_file_list(10);
+ char **sl = selectors[mmd->selector_num].get_audio_file_list(10);
int i;
if (!sl)
continue;
}
mmd->num_played++;
- if (dblist[mmd->dbt_num].update_audio_file)
- dblist[mmd->dbt_num].update_audio_file(sl[i]);
+ if (selectors[mmd->selector_num].update_audio_file)
+ selectors[mmd->selector_num].update_audio_file(sl[i]);
PARA_DEBUG_LOG("%s", "success\n");
mmd->new_afs_status_flags &= (~AFS_NEXT);
gettimeofday(&now, NULL);
if (chk_barrier("eof", &now, &eof_barrier, &the_timeout, 1) < 0)
return &the_timeout;
if (chk_barrier("data send", &now, &data_send_barrier,
- &the_timeout, 1) < 0)
+ &the_timeout, 1) < 0)
return &the_timeout;
if (mmd->audio_format < 0 || !afs_playing() || !audio_file)
return NULL;
return &the_timeout;
}
-static void afs_eof(struct audio_format *af)
+static void afs_eof(struct audio_format_handler *af)
{
struct timeval now;
int i;
free(tmp);
tmp = make_message("%s:\n%s:\n%s:\n", status_item_list[SI_DBINFO1],
status_item_list[SI_DBINFO2], status_item_list[SI_DBINFO3]);
- strcpy(mmd->dbinfo, tmp);
+ strcpy(mmd->selector_info, tmp);
free(tmp);
mmd->filename[0] = '\0';
mmd->size = 0;
mmd->events++;
}
+/**
+ * get the header and of the current audio file
+ *
+ * \param header_len the length of the header is stored here
+ *
+ * \return a pointer to a buffer containing the header, or NULL, if no audio
+ * file is selected or if the current audio format does not need special header
+ * treamtment.
+ *
+ */
+char *afs_get_header(int *header_len)
+{
+ *header_len = 0;
+ if (mmd->audio_format < 0)
+ return NULL;
+ if (!afl[mmd->audio_format].get_header_info)
+ return NULL;
+ return afl[mmd->audio_format].get_header_info(header_len);
+}
+const char *supported_audio_formats(void)
+{
+ return SUPPORTED_AUDIO_FORMATS;
+}
+
+/**
+ * get the chunk time of the current audio file
+ *
+ * \return a pointer to a struct containing the chunk time, or NULL,
+ * if currently no audio file is selected.
+ */
+struct timeval *afs_chunk_time(void)
+{
+ if (mmd->audio_format < 0)
+ return NULL;
+ return &afl[mmd->audio_format].chunk_tv;
+}
+
/**
* compute the timeout for para_server's main select-loop
*
* and acted upon by calling appropriate functions from the lower layers.
* Possible actions include
*
- * - request a new file list from the current dabase tool (audio file change)
+ * - request a new file list from the current audio file selector
* - shutdown of all senders (stop/pause command)
- * - repositioning of the stream (ff/jmp command)
+ * - reposition the stream (ff/jmp command)
*
* \return A pointer to a struct timeval containing the timeout for the next
* chunk of data to be sent, or NULL if we're not sending right now.
*/
struct timeval *afs_preselect(void)
{
- struct audio_format *af = NULL;
+ struct audio_format_handler *af = NULL;
int i, format;
struct timeval *ret;
again:
senders[i].shutdown_clients();
if (af) {
struct timeval now;
- if (!afs_paused() || mmd->chunks_sent) {
- gettimeofday(&now, NULL);
+ gettimeofday(&now, NULL);
+ if (!afs_paused() || mmd->chunks_sent)
tv_add(&af->eof_tv, &now, &eof_barrier);
- }
if (afs_repos())
tv_add(&now, &announce_tv, &data_send_barrier);
if (mmd->new_afs_status_flags & AFS_NOMORE)
mmd->new_afs_status_flags &= ~(AFS_REPOS);
mmd->current_chunk = mmd->repos_request;
}
- ret = afs_compute_timeout();
+ ret = afs_compute_timeout();
if (!ret && !audio_file && afs_playing() &&
!(mmd->new_afs_status_flags & AFS_NOMORE)) {
PARA_DEBUG_LOG("%s", "ready and playing, but no audio file\n");
void afs_send_chunk(void)
{
int i;
- struct audio_format *af;
+ struct audio_format_handler *af;
char *buf;
ssize_t ret;
struct timeval now, due;
afs_next_chunk_time(&due);
if (tv_diff(&due, &now, NULL) > 0)
return;
+ if (chk_barrier("eof", &now, &eof_barrier, &due, 1) < 0)
+ return;
+ if (chk_barrier("data send", &now, &data_send_barrier,
+ &due, 1) < 0)
+ return;
buf = af->read_chunk(mmd->current_chunk, &ret);
- mmd->new_afs_status_flags &= ~(AFS_NEXT | AFS_REPOS);
+ mmd->new_afs_status_flags &= ~AFS_REPOS;
if (!buf) {
if (ret < 0)
mmd->new_afs_status_flags = AFS_NEXT;
mmd->events++;
}
for (i = 0; senders[i].name; i++)
- senders[i].send(af, mmd->current_chunk,
- mmd->chunks_sent, buf, ret);
+ senders[i].send(mmd->current_chunk, mmd->chunks_sent, buf, ret);
mmd->new_afs_status_flags |= AFS_PLAYING;
mmd->chunks_sent++;
mmd->current_chunk++;