aacdec: detect buffer overrun and return an errror.
[paraslash.git] / afs.c
diff --git a/afs.c b/afs.c
index 4a4e46e..69b71e7 100644 (file)
--- a/afs.c
+++ b/afs.c
  * 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"
@@ -45,17 +46,20 @@ 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",
@@ -67,12 +71,18 @@ struct audio_format afl[] = {
                .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
@@ -150,7 +160,7 @@ void afs_init(void)
                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]);
@@ -165,25 +175,30 @@ static int get_file_info(int 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;
                }
        }
@@ -194,7 +209,7 @@ static int get_audio_format(int omit)
 {
        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);
@@ -327,7 +342,7 @@ static struct timeval *afs_compute_timeout(void)
        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;
@@ -360,6 +375,43 @@ static void afs_eof(struct audio_format *af)
        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
  *
@@ -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
  *
- *     - 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:
@@ -440,7 +492,7 @@ again:
 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;
@@ -452,6 +504,11 @@ void afs_send_chunk(void)
        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_REPOS;
        if (!buf) {
@@ -470,8 +527,7 @@ void afs_send_chunk(void)
                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++;