aacdec: detect buffer overrun and return an errror.
[paraslash.git] / afs.c
diff --git a/afs.c b/afs.c
index cb6c3882266876d240ddaaf1fb857d7cda75dbeb..69b71e77670769e254807d62f373c9d4f89e05e0 100644 (file)
--- a/afs.c
+++ b/afs.c
 
 /** \file afs.c audio file sending functions
  *
 
 /** \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 <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"
 #include "afs.h"
 #include "send.h"
 #include "error.h"
@@ -38,24 +39,27 @@ static struct timeval data_send_barrier;
 static struct timeval eof_barrier;
 
 extern struct misc_meta_data *mmd;
 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
 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
 #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
  */
 #endif
 
 /**
  * the list of supported  audio formats
  */
-struct audio_format afl[] = {
+static struct audio_format_handler afl[] = {
 #if 1
        {
                .name = "mp3",
 #if 1
        {
                .name = "mp3",
@@ -67,12 +71,18 @@ struct audio_format afl[] = {
                .name = "ogg",
                .init = ogg_init,
        },
                .name = "ogg",
                .init = ogg_init,
        },
+#endif
+#ifdef HAVE_FAAD
+       {
+               .name = "aac",
+               .init = aac_afh_init,
+       },
 #endif
        {
                .name = NULL,
        }
 };
 #endif
        {
                .name = NULL,
        }
 };
-
+#define FOR_EACH_AUDIO_FORMAT(i) for (i = 0; afl[i].name; i++)
 
 /**
  * check if audio file sender is playing
 
 /**
  * check if audio file sender is playing
@@ -150,7 +160,7 @@ void afs_init(void)
                afl[i].init(&afl[i]);
        }
        ms2tv(conf.announce_time_arg, &announce_tv);
                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]);
        for (i = 0; senders[i].name; i++) {
                PARA_NOTICE_LOG("initializing %s sender\n", senders[i].name);
                senders[i].init(&senders[i]);
@@ -165,25 +175,30 @@ static int get_file_info(int i)
                &mmd->chunks_total, &mmd->seconds_total);
 }
 
                &mmd->chunks_total, &mmd->seconds_total);
 }
 
-/*
+/**
  * guess the audio format judging from filename
  * 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.
  */
  * \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;
                }
        }
                        return i;
                }
        }
@@ -194,7 +209,7 @@ static int get_audio_format(int omit)
 {
        int 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);
                if (i == omit || !afl[i].get_file_info)
                        continue;
                rewind(audio_file);
@@ -233,7 +248,7 @@ static int update_mmd(void)
 
 static void get_song(void)
 {
 
 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)
        int i;
 
        if (!sl)
@@ -253,8 +268,8 @@ static void get_song(void)
                        continue;
                }
                mmd->num_played++;
                        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);
                PARA_DEBUG_LOG("%s", "success\n");
                mmd->new_afs_status_flags &= (~AFS_NEXT);
                gettimeofday(&now, NULL);
@@ -313,7 +328,7 @@ static struct timeval *afs_compute_timeout(void)
        if (chk_barrier("eof", &now, &eof_barrier, &the_timeout, 1) < 0)
                return &the_timeout;
        if (chk_barrier("data send", &now, &data_send_barrier,
        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;
        if (mmd->audio_format < 0 || !afs_playing() || !audio_file)
                return NULL;
@@ -327,7 +342,7 @@ static struct timeval *afs_compute_timeout(void)
        return &the_timeout;
 }
 
        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;
 {
        struct timeval now;
        int i;
@@ -353,13 +368,50 @@ static void afs_eof(struct audio_format *af)
        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]);
        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++;
 }
 
        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
  *
 /**
  * compute the timeout for para_server's main select-loop
  *
@@ -370,16 +422,16 @@ static void afs_eof(struct audio_format *af)
  * and acted upon by calling appropriate functions from the lower layers.
  * Possible actions include
  *
  * 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)
  *     - 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)
 {
  *
  * \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:
        int i, format;
        struct timeval *ret;
 again:
@@ -398,10 +450,9 @@ again:
                        senders[i].shutdown_clients();
                if (af) {
                        struct timeval now;
                        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);
                                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)
                        if (afs_repos())
                                tv_add(&now, &announce_tv, &data_send_barrier);
                        if (mmd->new_afs_status_flags & AFS_NOMORE)
@@ -415,7 +466,7 @@ again:
                mmd->new_afs_status_flags &= ~(AFS_REPOS);
                mmd->current_chunk = mmd->repos_request;
        }
                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");
        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");
@@ -441,7 +492,7 @@ again:
 void afs_send_chunk(void)
 {
        int i;
 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;
        char *buf;
        ssize_t ret;
        struct timeval now, due;
@@ -453,8 +504,13 @@ void afs_send_chunk(void)
        afs_next_chunk_time(&due);
        if (tv_diff(&due, &now, NULL) > 0)
                return;
        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);
        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;
        if (!buf) {
                if (ret < 0)
                        mmd->new_afs_status_flags = AFS_NEXT;
@@ -471,8 +527,7 @@ void afs_send_chunk(void)
                mmd->events++;
        }
        for (i = 0; senders[i].name; i++)
                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++;
        mmd->new_afs_status_flags |= AFS_PLAYING;
        mmd->chunks_sent++;
        mmd->current_chunk++;