]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Merge ../paraslash_meins/paraslash
authorAndre Noll <maan@congo.fml.local>
Mon, 12 Mar 2007 15:10:05 +0000 (16:10 +0100)
committerAndre Noll <maan@congo.fml.local>
Mon, 12 Mar 2007 15:10:05 +0000 (16:10 +0100)
README.mysql
aac_afh.c
afh.h
command.c
fd.c
mp3_afh.c
ogg_afh.c
server.c
server.h
vss.c

index 986afb307e82bf4e46a658556a41eec4a15f4935..4531a32c879f4b69b133f6d5220a6487d27103d8 100644 (file)
@@ -23,9 +23,9 @@ Remember: If something doesn't work as expected, look at the server
 log file and/or increase output verbosity by using the -l switch for
 server and client.
 
-------------------------------------
+-------------------------------------
 Specify mysql data (port, passwd,...)
-------------------------------------
+-------------------------------------
 
 Type
 
@@ -64,11 +64,11 @@ more info) or that para_server was built without mysql support. Type
 
 to find out. If mysql is not mentioned as a supported selector,
 you'll have to recompile. If configure does not detect your mysql
-installation, use the --enable-mysql-headers and --enable-mysql-libs
+installation, use the --with-mysql-headers and --with-mysql-libs
 options to specify the mysql path explicitly . Example:
 
-       ./configure --enable-mysql-headers=/Library/MySQL/include \
-               --enable-mysql-libs=/Library/MySQL/lib/mysql
+       ./configure --with-mysql-headers=/Library/MySQL/include \
+               --with-mysql-libs=/Library/MySQL/lib/mysql
 
 
 ---------------------
index 956ff6dad37493e5cf95990cde50204f97c226a3..c268255a7026df872a6e0d8c17b06b2bdee5ea96 100644 (file)
--- a/aac_afh.c
+++ b/aac_afh.c
 #include "server.cmdline.h"
 #include "server.h"
 #include "vss.h"
-#include "afh.h"
 #include "error.h"
 #include "string.h"
 #include "aac.h"
 #include "fd.h"
 
 /** size of the input buffer, must be big enough to hold header */
-#define DEFAULT_INBUF_SIZE 65536
-
-static struct audio_format_handler *af;
-static FILE *infile;
-static unsigned char *inbuf;
-static size_t inbuf_size, inbuf_len, *chunk_table, num_chunks;
-
-static void aac_close_audio_file(void)
-{
-       if (!infile)
-               return;
-       fclose(infile);
-       infile = NULL;
-       free(inbuf);
-       inbuf = NULL;
-       free(chunk_table);
-       chunk_table = NULL;
-}
+#define AAC_INBUF_SIZE 65536
 
 static int aac_find_stsz(unsigned char *buf, unsigned buflen, size_t *skip)
 {
@@ -76,7 +58,8 @@ static int aac_find_stsz(unsigned char *buf, unsigned buflen, size_t *skip)
        return -E_STSZ;
 }
 
-static int read_chunk_table(size_t skip)
+static int read_chunk_table(FILE *file, struct audio_format_info *afi,
+               unsigned char *inbuf, size_t inbuf_len, size_t skip)
 {
        int ret, i;
        size_t sum = 0;
@@ -85,19 +68,21 @@ static int read_chunk_table(size_t skip)
                ret = aac_find_stsz(inbuf, inbuf_len, &skip);
                if (ret >= 0)
                        break;
-               ret = read(fileno(infile), inbuf, inbuf_size);
+               ret = read(fileno(file), inbuf, AAC_INBUF_SIZE);
                if (ret <= 0)
                        return -E_AAC_READ;
+               inbuf_len = ret;
                PARA_INFO_LOG("next buffer: %d bytes\n", ret);
        }
-       num_chunks = ret;
-       PARA_INFO_LOG("sz table has %zu entries\n", num_chunks);
-       chunk_table = para_malloc((num_chunks + 1) * sizeof(size_t));
-       for (i = 1; i <= num_chunks; i++) {
+       afi->chunks_total = ret;
+       PARA_INFO_LOG("sz table has %lu entries\n", afi->chunks_total);
+       afi->chunk_table = para_malloc((afi->chunks_total + 1) * sizeof(size_t));
+       for (i = 1; i <= afi->chunks_total; i++) {
                if (skip + 4 > inbuf_len) {
                        skip = inbuf_len - skip;
                        memmove(inbuf, inbuf + inbuf_len - skip, skip);
-                       ret = read(fileno(infile), inbuf + skip, inbuf_size - skip);
+                       ret = read(fileno(file), inbuf + skip,
+                               AAC_INBUF_SIZE - skip);
                        if (ret <= 0)
                                return -E_AAC_READ;
                        inbuf_len = ret + skip;
@@ -105,98 +90,102 @@ static int read_chunk_table(size_t skip)
                        PARA_INFO_LOG("next buffer: %zu bytes\n", inbuf_len);
                }
                sum += aac_read_int32(inbuf + skip);
-               chunk_table[i] = sum;
+               afi->chunk_table[i] = sum;
                skip += 4;
-               if (i < 10 || i + 10 > num_chunks)
-                       PARA_DEBUG_LOG("offset #%d: %zu\n", i, chunk_table[i]);
+//             if (i < 10 || i + 10 > afi->chunks_total)
+//                     PARA_DEBUG_LOG("offset #%d: %zu\n", i, afi->chunk_table[i]);
        }
        return 1;
 }
 
-static long unsigned aac_set_chunk_tv(mp4AudioSpecificConfig *mp4ASC)
+static long unsigned aac_set_chunk_tv(struct audio_format_info *afi,
+               mp4AudioSpecificConfig *mp4ASC)
 {
        float tmp = mp4ASC->sbr_present_flag == 1? 2047 : 1023,
-               ms = 1000.0 * num_chunks * tmp / mp4ASC->samplingFrequency;
+               ms = 1000.0 * afi->chunks_total * tmp / mp4ASC->samplingFrequency;
        struct timeval total;
 
        ms2tv(ms, &total);
-       tv_divide(num_chunks, &total, &af->chunk_tv);
-       PARA_INFO_LOG("%luHz, %fs (%zd x %lums)\n",
+       tv_divide(afi->chunks_total, &total, &afi->chunk_tv);
+       PARA_INFO_LOG("%luHz, %fs (%lu x %lums)\n",
                mp4ASC->samplingFrequency, ms / 1000,
-               num_chunks, tv2ms(&af->chunk_tv));
+               afi->chunks_total, tv2ms(&afi->chunk_tv));
        return ms / 1000;
 }
 
 /*
  * Init m4a file and write some tech data to given pointers.
  */
-static int aac_get_file_info(FILE *file, char *info_str, long unsigned *frames,
-       int *seconds, size_t **vss_chunk_table)
+static int aac_get_file_info(FILE *file, struct audio_format_info *afi)
 {
        int i, ret, decoder_len;
-       size_t skip;
+       size_t inbuf_len, skip;
        unsigned long rate = 0;
-       unsigned char channels = 0;
+       unsigned char channels = 0, *inbuf = para_malloc(AAC_INBUF_SIZE);
        mp4AudioSpecificConfig mp4ASC;
        NeAACDecHandle handle;
 
-       inbuf_size = DEFAULT_INBUF_SIZE;
-       inbuf = para_malloc(inbuf_size);
-       infile = file;
-
-       ret = read(fileno(infile), inbuf, inbuf_size);
-       if (ret <= 0)
-               return -E_AAC_READ;
+       ret = read(fileno(file), inbuf, AAC_INBUF_SIZE);
+       if (ret <= 0) {
+               ret = -E_AAC_READ;
+               goto out;
+       }
        inbuf_len = ret;
        ret = aac_find_esds(inbuf, inbuf_len, &skip);
        if (ret < 0)
-               return ret;
+               goto out;
        decoder_len = ret;
        handle = aac_open();
-       ret = NeAACDecInit(handle, inbuf + skip,
-               decoder_len, &rate, &channels);
-       if (ret < 0)
-               return -E_AACDEC_INIT;
+       ret = NeAACDecInit(handle, inbuf + skip, decoder_len, &rate, &channels);
+       if (ret < 0) {
+               ret = -E_AACDEC_INIT;
+               goto out;
+       }
        skip += ret;
        PARA_INFO_LOG("rate: %lu, channels: %d\n", rate, channels);
-       ret = NeAACDecAudioSpecificConfig(inbuf + skip, inbuf_len - skip,
-               &mp4ASC);
+       ret = -E_MP4ASC;
+       if (NeAACDecAudioSpecificConfig(inbuf + skip, inbuf_len - skip,
+                       &mp4ASC) < 0)
+               goto out;
+       ret = read_chunk_table(file, afi, inbuf, inbuf_len, skip);
        if (ret < 0)
-               return -E_MP4ASC;
-       ret = read_chunk_table(skip);
-       if (ret < 0)
-               return ret;
-       *frames = num_chunks;
-       *seconds = aac_set_chunk_tv(&mp4ASC);
-       *vss_chunk_table = chunk_table;
+               goto out;
+       afi->seconds_total = aac_set_chunk_tv(afi, &mp4ASC);
        for (;;) {
                ret = aac_find_entry_point(inbuf, inbuf_len, &skip);
                if (ret >= 0)
                        break;
-               ret = read(fileno(infile), inbuf, inbuf_size);
-               if (ret <= 0)
-                       return -E_AAC_READ;
+               ret = read(fileno(file), inbuf, AAC_INBUF_SIZE);
+               if (ret <= 0) {
+                       ret = -E_AAC_READ;
+                       goto out;
+               }
+               inbuf_len = ret;
                PARA_INFO_LOG("next buffer: %d bytes\n", ret);
        }
-       chunk_table[0] = ret;
-       for (i = 1; i<= num_chunks; i++)
-               chunk_table[i] += ret;
-       sprintf(info_str, "audio_file_info1:%zu x %lums\n"
+       afi->chunk_table[0] = ret;
+       for (i = 1; i<= afi->chunks_total; i++)
+               afi->chunk_table[i] += ret;
+       sprintf(afi->info_string, "audio_file_info1:%lu x %lums\n"
                "audio_file_info2:\n"
                "audio_file_info3:\n",
-               num_chunks,
-               tv2ms(&af->chunk_tv));
-       tv_scale(20, &af->chunk_tv, &af->eof_tv);
-       return 1;
+               afi->chunks_total,
+               tv2ms(&afi->chunk_tv));
+       tv_scale(20, &afi->chunk_tv, &afi->eof_tv);
+       ret = 1;
+out:
+       free(inbuf);
+       return ret;
 }
 
 static const char* aac_suffixes[] = {"m4a", "mp4", NULL};
-/** the init function of the aac audio format handler */
-void aac_afh_init(struct audio_format_handler *p)
+/**
+ * the init function of the aac audio format handler
+ *
+ * \param afh pointer to the struct to initialize
+ */
+void aac_afh_init(struct audio_format_handler *afh)
 {
-       af = p;
-       af->get_file_info = aac_get_file_info,
-       af->close_audio_file = aac_close_audio_file;
-       af->get_header_info = NULL;
-       af->suffixes = aac_suffixes;
+       afh->get_file_info = aac_get_file_info,
+       afh->suffixes = aac_suffixes;
 }
diff --git a/afh.h b/afh.h
index 77874108a056c73707f2b39516168558bf1b4e80..daac3279729ab5f9001a2f4e15366b21943c2d1e 100644 (file)
--- a/afh.h
+++ b/afh.h
 
 /** \endcond */
 
+/** size of the  audio_file info string */
+#define AUDIO_FILE_INFO_SIZE 16384
+
+struct audio_format_info {
+       /** the number of chunks this audio file contains */
+       long unsigned chunks_total;
+       /** the length of the audio file in seconds */
+       int seconds_total;
+       /** a string that gets filled in by the audio format handler */
+       char info_string[AUDIO_FILE_INFO_SIZE];
+       /**
+        * the table that specifies the offset of the individual pieces in
+        * the current audio file.
+        */
+       size_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;
+       /**
+        * optional audio file header
+        *
+        * This is read from a sender in case a new client connects in the
+        * middle of the stream.  The audio format handler does not need to set
+        * this if the audio format does not need any special header treatment.
+        * If non-NULL, it must point to a buffer holding the current audio
+        * file header.
+        */
+       char *header;
+       /** the length of the header, ignored if \a header is \p NULL */
+       unsigned header_len;
+};
+
 /**
  * structure for audio format handling
  *
@@ -64,43 +97,17 @@ struct audio_format_handler {
         * Must initialize all function pointers and is assumed to succeed.
         */
        void (*init)(struct audio_format_handler*);
-       /**
-        * period of time between sending data chunks
-       */
-       struct timeval chunk_tv; /* length of one chunk of data */
-       /**
-        * end of file timeout - do not load new audio file until this time
-        *
-       */
-       struct timeval eof_tv; /* timeout on eof */
-       /**
-        * Pointer to the optional get-header function.
-        *
-        * This is called from a sender in case a new client connects in the middle of
-        * the stream.  The audio format handler may set this to NULL to indicate that
-        * this audio format does not need any special header treatment.  If non-NULL,
-        * the function it points to must return a pointer to a buffer holding the
-        * current audio file header, together with the header length.
-       */
-       char *(*get_header_info)(int *header_len);
        /**
         * check if this audio format handler can handle the file
         *
-        * This is a  pointer to a function returning whether a given file is valid for
-        * this audio format. A negative return value indicates that this audio format
-        * handler did not recognize the given file. On success, the function is
-        * expected to return a positive value and to fill in \arg info_str, \arg
-        * chunks and \arg seconds appropriately and to return the chunk table
-        * via \a vss_chunk_table.
-       */
-       int (*get_file_info)(FILE *audio_file, char *info_str,
-               long unsigned *chunks, int *seconds, size_t **vss_chunk_table);
-       /**
-        * cleanup function of this audio format handler
+        * This is a  pointer to a function returning whether a given file is
+        * valid for this audio format. A negative return value indicates that
+        * this audio format handler did not recognize the given file. On
+        * success, the function must return a positive value and fill in the
+        * given struct audio_format_info.
         *
-        * This close function should deallocate any resources
-        * associated with the current audio file. In particular, it is responsible
-        * for closing the file handle. It is assumed to succeed.
+        * \sa struct audio_format_info
        */
-       void (*close_audio_file)(void);
+       int (*get_file_info)(FILE *audio_file, struct audio_format_info *afi);
 };
+
index 77d3ef7f0ddd223b0408285f1df18e61b45ddd6f..de56ce8296fdf5d451c5a16b7cd08f2cddc47e1a 100644 (file)
--- a/command.c
+++ b/command.c
@@ -45,7 +45,6 @@ extern const char *status_item_list[NUM_STAT_ITEMS];
 extern struct misc_meta_data *mmd;
 extern struct audio_file_selector selectors[];
 extern struct sender senders[];
-extern char *user_list;
 
 static void dummy(__a_unused int s)
 {}
@@ -114,14 +113,14 @@ static char *get_sb_string(struct misc_meta_data *nmmd)
                return para_strdup("");
        if (!base[0])
                return base;
-       if (nmmd->chunks_total) {
-               secs = (long long) nmmd->seconds_total * nmmd->chunks_sent
-                       / nmmd->chunks_total;
-               rsecs = (long long) nmmd->seconds_total *
-                       (nmmd->chunks_total - nmmd->chunks_sent)
-                       / nmmd->chunks_total;
+       if (nmmd->afi.chunks_total) {
+               secs = (long long) nmmd->afi.seconds_total * nmmd->chunks_sent
+                       / nmmd->afi.chunks_total;
+               rsecs = (long long) nmmd->afi.seconds_total *
+                       (nmmd->afi.chunks_total - nmmd->chunks_sent)
+                       / nmmd->afi.chunks_total;
                percent = 100 * ((nmmd->chunks_sent + 5) / 10)
-                       / ((nmmd->chunks_total + 5) / 10);
+                       / ((nmmd->afi.chunks_total + 5) / 10);
        }
        ret = make_message("%llu:%02llu [%llu:%02llu] (%llu%%) %s",
                secs / 60, secs % 60,
@@ -158,7 +157,7 @@ static char *get_status(struct misc_meta_data *nmmd)
                "%s:%s\n"       "%s:%lu.%lu\n"  "%s:%lu.%lu\n",
                status_item_list[SI_FILE_SIZE], nmmd->size / 1024,
                status_item_list[SI_MTIME], mtime,
-               status_item_list[SI_LENGTH], nmmd->seconds_total,
+               status_item_list[SI_LENGTH], nmmd->afi.seconds_total,
                status_item_list[SI_NUM_PLAYED], nmmd->num_played,
 
                status_item_list[SI_STATUS_BAR], bar ? bar : "(none)",
@@ -169,7 +168,7 @@ static char *get_status(struct misc_meta_data *nmmd)
                status_item_list[SI_OFFSET], offset,
                status_item_list[SI_FORMAT], audio_format_name(nmmd->audio_format),
                nmmd->selector_info,
-               nmmd->audio_file_info,
+               nmmd->afi.info_string,
 
                status_item_list[SI_UPTIME], ut,
                status_item_list[SI_STREAM_START],
@@ -649,20 +648,20 @@ int com_ff(__a_unused int fd, int argc, char **argv)
                backwards = 1; /* jmp backwards */
        mmd_lock();
        ret = -E_NO_AUDIO_FILE;
-       if (!mmd->chunks_total || !mmd->seconds_total)
+       if (!mmd->afi.chunks_total || !mmd->afi.seconds_total)
                goto out;
-       promille = (1000 * mmd->current_chunk) / mmd->chunks_total;
+       promille = (1000 * mmd->current_chunk) / mmd->afi.chunks_total;
        if (backwards)
-               promille -= 1000 * i / mmd->seconds_total;
+               promille -= 1000 * i / mmd->afi.seconds_total;
        else
-               promille += 1000 * i / mmd->seconds_total;
+               promille += 1000 * i / mmd->afi.seconds_total;
        if (promille < 0)
                promille = 0;
        if (promille >  1000) {
                mmd->new_vss_status_flags |= VSS_NEXT;
                goto out;
        }
-       mmd->repos_request = (mmd->chunks_total * promille) / 1000;
+       mmd->repos_request = (mmd->afi.chunks_total * promille) / 1000;
        mmd->new_vss_status_flags |= VSS_REPOS;
        mmd->new_vss_status_flags &= ~VSS_NEXT;
        mmd->events++;
@@ -684,12 +683,12 @@ int com_jmp(__a_unused int fd, int argc, char **argv)
                return -E_COMMAND_SYNTAX;
        mmd_lock();
        ret = -E_NO_AUDIO_FILE;
-       if (!mmd->chunks_total)
+       if (!mmd->afi.chunks_total)
                goto out;
        if (i > 100)
                i = 100;
        PARA_INFO_LOG("jumping to %lu%%\n", i);
-       mmd->repos_request = (mmd->chunks_total * i + 50)/ 100;
+       mmd->repos_request = (mmd->afi.chunks_total * i + 50)/ 100;
        PARA_INFO_LOG("sent: %lu,  offset before jmp: %lu\n",
                mmd->chunks_sent, mmd->offset);
        mmd->new_vss_status_flags |= VSS_REPOS;
diff --git a/fd.c b/fd.c
index df7921b4f393c4b4c2bcfc963c757c0a67aec661..637884b4b895a9279c5c928ea4028dbddb1a74c7 100644 (file)
--- a/fd.c
+++ b/fd.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 2006-2007 Andre Noll <maan@systemlinux.org>
  *
  *     This program is free software; you can redistribute it and/or modify
  *     it under the terms of the GNU General Public License as published by
@@ -167,8 +167,19 @@ again:
        goto again;
 }
 
+/**
+ * paralash's wrapper for fseek(3)
+ *
+ * \param stream stream to seek
+ * \param offset added to the position specified by whence
+ * \param whence \p SEEK_SET, \p SEEK_CUR, or \p SEEK_END
+ *
+ * \return positive on success, -E_FSEEK on errors.
+ *
+ * \sa fseek(3)
+ */
 int para_fseek(FILE *stream, long offset, int whence)
 {
        int ret = fseek(stream, offset, whence);
-       return ret < 0? -E_FSEEK : ret;
+       return ret < 0? -E_FSEEK : 1;
 }
index 7146124803e6c13420e404df919090cb4f556940..e2ed10cfabc094f1cd89a6f1ba152c38cc8e0ad6 100644 (file)
--- a/mp3_afh.c
+++ b/mp3_afh.c
@@ -31,7 +31,6 @@
 #include "server.cmdline.h"
 #include "server.h"
 #include "vss.h"
-#include "afh.h"
 #include "error.h"
 #include "fd.h"
 #include "string.h"
@@ -43,7 +42,6 @@
  * to see before we decide we are looking at a real MP3 file
  */
 #define MIN_CONSEC_GOOD_FRAMES 4
-
 #define FRAME_HEADER_SIZE 4
 #define MIN_FRAME_SIZE 21
 
@@ -75,7 +73,6 @@ struct mp3info {
        struct id3tag id3;
        int vbr;
        long unsigned br_average;
-       long unsigned seconds;
        int freq;
 };
 
@@ -103,10 +100,7 @@ static const int mp3info_bitrate[2][3][14] = {
 static const int frame_size_index[] = {24000, 72000, 72000};
 static const char *mode_text[] = {"stereo", "joint stereo", "dual channel", "mono", "invalid"};
 
-static FILE *infile;
 static struct mp3info mp3;
-static struct audio_format_handler *af;
-static ssize_t *chunk_table, num_chunks;
 
 static int header_frequency(struct mp3header *h)
 {
@@ -144,16 +138,16 @@ static int frame_length(struct mp3header *header)
                + header->padding;
 }
 
-static void write_info_str(char *info_str)
+static void write_info_str(struct audio_format_info *afi)
 {
        int v = mp3.id3_isvalid;
 
-       snprintf(info_str, MMD_INFO_SIZE,
-               "audio_file_info1:%d x %lums, %lu kbit/s (%cbr) %i KHz %s\n"
+       snprintf(afi->info_string, MMD_INFO_SIZE,
+               "audio_file_info1:%lu x %lums, %lu kbit/s (%cbr) %i KHz %s\n"
                "audio_file_info2:%s, by %s\n"
                "audio_file_info3:A: %s, Y: %s, C: %s\n",
-               num_chunks,
-               tv2ms(&af->chunk_tv),
+               afi->chunks_total,
+               tv2ms(&afi->chunk_tv),
                mp3.br_average,
                mp3.vbr? 'v' : 'c',
                mp3.freq / 1000,
@@ -245,36 +239,36 @@ static int get_header(FILE *file, struct mp3header *header)
  * returned.
  *
  */
-static int mp3_seek_next_header(void)
+static int mp3_seek_next_header(FILE *file)
 {
        int k, l = 0, c, first_len, ret;
        struct mp3header h, h2;
        long valid_start = 0;
 
        while (1) {
-               while ((c = fgetc(infile)) != 255 && (c != EOF))
+               while ((c = fgetc(file)) != 255 && (c != EOF))
                        ; /* nothing */
                if (c != 255)
                        return 0;
-               ungetc(c, infile);
-               valid_start = ftell(infile);
-               first_len = get_header(infile, &h);
+               ungetc(c, file);
+               valid_start = ftell(file);
+               first_len = get_header(file, &h);
                if (first_len <= 0)
                        continue;
-               ret = para_fseek(infile, first_len - FRAME_HEADER_SIZE, SEEK_CUR);
+               ret = para_fseek(file, first_len - FRAME_HEADER_SIZE, SEEK_CUR);
                if (ret < 0)
                        return ret;
                for (k = 1; k < MIN_CONSEC_GOOD_FRAMES; k++) {
-                       if ((l = get_header(infile, &h2)) <= 0)
+                       if ((l = get_header(file, &h2)) <= 0)
                                break;
                        if (!compare_headers(&h, &h2))
                                break;
-                       ret = para_fseek(infile, l - FRAME_HEADER_SIZE, SEEK_CUR);
+                       ret = para_fseek(file, l - FRAME_HEADER_SIZE, SEEK_CUR);
                        if (ret < 0)
                                return ret;
                }
                if (k == MIN_CONSEC_GOOD_FRAMES) {
-                       ret = para_fseek(infile, valid_start, SEEK_SET);
+                       ret = para_fseek(file, valid_start, SEEK_SET);
                        if (ret < 0)
                                return ret;
                        memcpy(&(mp3.header), &h2, sizeof(struct mp3header));
@@ -283,7 +277,7 @@ static int mp3_seek_next_header(void)
        }
 }
 
-static int mp3_get_id3(void)
+static int mp3_get_id3(FILE *file)
 {
        char fbuf[4];
        int ret;
@@ -294,32 +288,32 @@ static int mp3_get_id3(void)
        mp3.id3.album[0] = '\0';
        mp3.id3.comment[0] = '\0';
        mp3.id3.year[0] = '\0';
-       ret = para_fseek(infile, -128, SEEK_END);
+       ret = para_fseek(file, -128, SEEK_END);
        if (ret < 0 )
                return ret;
-       if (para_fread(fbuf, 1, 3, infile) < 0)
+       if (para_fread(fbuf, 1, 3, file) < 0)
                return -E_FREAD;
        fbuf[3] = '\0';
        if (strcmp("TAG", fbuf)) {
                PARA_INFO_LOG("%s", "no id3 tag\n");
                return 0;
        }
-       ret = para_fseek(infile, -125, SEEK_END);
+       ret = para_fseek(file, -125, SEEK_END);
        if (ret < 0)
                return ret;
-       if (para_fread(mp3.id3.title, 1, 30, infile) != 30)
+       if (para_fread(mp3.id3.title, 1, 30, file) != 30)
                return -E_FREAD;
        mp3.id3.title[30] = '\0';
-       if (para_fread(mp3.id3.artist, 1, 30, infile) != 30)
+       if (para_fread(mp3.id3.artist, 1, 30, file) != 30)
                return -E_FREAD;
        mp3.id3.artist[30] = '\0';
-       if (para_fread(mp3.id3.album, 1, 30, infile) != 30)
+       if (para_fread(mp3.id3.album, 1, 30, file) != 30)
                return -E_FREAD;
        mp3.id3.album[30] = '\0';
-       if (para_fread(mp3.id3.year, 1, 4, infile) != 4)
+       if (para_fread(mp3.id3.year, 1, 4, file) != 4)
                return -E_FREAD;
        mp3.id3.year[4] = '\0';
-       if (para_fread(mp3.id3.comment, 1, 30, infile) != 30)
+       if (para_fread(mp3.id3.comment, 1, 30, file) != 30)
                return -E_FREAD;
        mp3.id3.comment[30] = '\0';
        mp3.id3_isvalid = 1;
@@ -331,21 +325,19 @@ static int mp3_get_id3(void)
        return 1;
 }
 
-static int find_valid_start(void)
+static int find_valid_start(FILE *file)
 {
        int ret, frame_len;
 
-       if (!infile)
-               return -E_MP3_NO_FILE;
-       frame_len = get_header(infile, &mp3.header);
+       frame_len = get_header(file, &mp3.header);
        if (frame_len < 0)
                return frame_len;
        if (!frame_len) {
-               frame_len = mp3_seek_next_header();
+               frame_len = mp3_seek_next_header(file);
                if (frame_len <= 0)
                        return frame_len;
        } else {
-               ret = para_fseek(infile, -FRAME_HEADER_SIZE, SEEK_CUR);
+               ret = para_fseek(file, -FRAME_HEADER_SIZE, SEEK_CUR);
                if (ret < 0)
                        return ret;
        }
@@ -354,30 +346,30 @@ static int find_valid_start(void)
        return frame_len;
 }
 
-static int mp3_read_info(void)
+static int mp3_read_info(FILE *file, struct audio_format_info *afi)
 {
        long fl_avg = 0, freq_avg = 0, br_avg = 0;
        int ret, len = 0, old_br = -1;
        struct timeval total_time = {0, 0};
        unsigned chunk_table_size = 1000; /* gets increased on demand */
 
-       num_chunks = 0;
-       chunk_table = para_malloc(chunk_table_size * sizeof(size_t));
-       ret = mp3_get_id3();
+       afi->chunks_total = 0;
+       afi->chunk_table = para_malloc(chunk_table_size * sizeof(size_t));
+       ret = mp3_get_id3(file);
        if (ret < 0)
                goto err_out;
-       rewind(infile);
+       rewind(file);
        mp3.vbr = 0;
        mp3.freq = 0;
        while (1) {
                int freq, br, fl;
                struct timeval tmp, cct; /* current chunk time */
                if (len > 0) {
-                       ret = para_fseek(infile, len, SEEK_CUR);
+                       ret = para_fseek(file, len, SEEK_CUR);
                        if (ret < 0)
                                goto err_out;
                }
-               len = find_valid_start();
+               len = find_valid_start(file);
                if (len <= 0)
                        break;
                freq = header_frequency(&mp3.header);
@@ -391,103 +383,78 @@ static int mp3_read_info(void)
                tv_add(&cct, &total_time, &tmp);
                total_time = tmp;
                //PARA_DEBUG_LOG("%s: br: %d, freq: %d, fl: %d, cct: %lu\n", __func__, br, freq, fl, cct.tv_usec);
-               if (num_chunks >= chunk_table_size) {
+               if (afi->chunks_total >= chunk_table_size) {
                        chunk_table_size *= 2;
-                       chunk_table = para_realloc(chunk_table,
+                       afi->chunk_table = para_realloc(afi->chunk_table,
                                chunk_table_size * sizeof(size_t));
                }
-               chunk_table[num_chunks] = ftell(infile);
-               if (num_chunks < 10 || !(num_chunks % 1000))
-                       PARA_INFO_LOG("chunk #%d: %zd\n", num_chunks,
-                               chunk_table[num_chunks]);
-               num_chunks++;
-               if (num_chunks == 1) {
-//                     entry = ftell(infile);
-//                     PARA_INFO_LOG("entry: %zd\n", entry);
+               afi->chunk_table[afi->chunks_total] = ftell(file);
+//             if (afi->chunks_total < 10 || !(afi->chunks_total % 1000))
+//                     PARA_INFO_LOG("chunk #%lu: %zd\n", afi->chunks_total,
+//                             afi->chunk_table[afi->chunks_total]);
+               afi->chunks_total++;
+               if (afi->chunks_total == 1) {
                        freq_avg = freq;
                        br_avg = br;
                        old_br = br;
                        fl_avg = fl;
                        continue;
                }
-               freq_avg += (freq - freq_avg) / (num_chunks + 1);
-               fl_avg += (fl - fl_avg) / (num_chunks + 1);
-               br_avg += (br - br_avg) / (num_chunks + 1);
+               freq_avg += (freq - freq_avg) / (afi->chunks_total + 1);
+               fl_avg += (fl - fl_avg) / (afi->chunks_total + 1);
+               br_avg += (br - br_avg) / (afi->chunks_total + 1);
                if (old_br != br)
                        mp3.vbr = 1;
                old_br = br;
        }
        ret = -E_MP3_INFO;
-       if (!num_chunks || !freq_avg || !br_avg)
+       if (!afi->chunks_total || !freq_avg || !br_avg)
                goto err_out;
-       ret= para_fseek(infile, 0, SEEK_END);
+       ret= para_fseek(file, 0, SEEK_END);
        if (ret < 0)
                goto err_out;
-       chunk_table[num_chunks] = ftell(infile);
+       afi->chunk_table[afi->chunks_total] = ftell(file);
        mp3.br_average = br_avg;
        mp3.freq = freq_avg;
-       mp3.seconds = (tv2ms(&total_time) + 500) / 1000;
-       tv_divide(num_chunks, &total_time, &af->chunk_tv);
-       rewind(infile);
-       PARA_DEBUG_LOG("%zu chunks, each %lums\n", num_chunks, tv2ms(&af->chunk_tv));
-       tv_scale(3, &af->chunk_tv, &af->eof_tv);
-       PARA_DEBUG_LOG("eof timeout: %lu\n", tv2ms(&af->eof_tv));
+       afi->seconds_total = (tv2ms(&total_time) + 500) / 1000;
+       tv_divide(afi->chunks_total, &total_time, &afi->chunk_tv);
+       rewind(file);
+       PARA_DEBUG_LOG("%lu chunks, each %lums\n", afi->chunks_total,
+               tv2ms(&afi->chunk_tv));
+       tv_scale(3, &afi->chunk_tv, &afi->eof_tv);
+       PARA_DEBUG_LOG("eof timeout: %lu\n", tv2ms(&afi->eof_tv));
        return 1;
 err_out:
        PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
-       free(chunk_table);
+       free(afi->chunk_table);
        return ret;
 }
 
 /*
  * Read mp3 information from audio file
  */
-static int mp3_get_file_info(FILE *audio_file, char *info_str,
-       long unsigned *frames, int *seconds, size_t **vss_chunk_table)
+static int mp3_get_file_info(FILE *file, struct audio_format_info *afi)
 {
        int ret;
 
-       if (!audio_file)
-               return -E_MP3_NO_FILE;
-       infile = audio_file;
-       ret = mp3_read_info();
-       if (ret < 0) {
-               infile = NULL;
+       ret = mp3_read_info(file, afi);
+       if (ret < 0)
                return ret;
-       }
-       write_info_str(info_str);
-       *frames = num_chunks;
-       *seconds = mp3.seconds;
-       *vss_chunk_table = chunk_table;
-       if (*seconds < 2 || !*frames)
+       write_info_str(afi);
+       if (afi->seconds_total < 2 || !afi->chunks_total)
                return -E_MP3_INFO;
        return 1;
 }
 
-static void mp3_close_audio_file(void)
-{
-       if (!infile)
-               return;
-       fclose(infile);
-       infile = NULL;
-       free(chunk_table);
-}
-
 static const char* mp3_suffixes[] = {"mp3", NULL};
 
 /**
  * the init function of the mp3 audio format handler
  *
- * \param p pointer to the struct to initialize
+ * \param afh pointer to the struct to initialize
  */
-void mp3_init(struct audio_format_handler *p)
+void mp3_init(struct audio_format_handler *afh)
 {
-       af = p;
-       af->get_file_info = mp3_get_file_info;
-       af->close_audio_file = mp3_close_audio_file;
-       af->get_header_info = NULL;
-       /* eof_tv gets overwritten in mp3_get_file_info() */
-       af->eof_tv.tv_sec = 0;
-       af->eof_tv.tv_usec = 100 * 1000;
-       af->suffixes = mp3_suffixes;
+       afh->get_file_info = mp3_get_file_info;
+       afh->suffixes = mp3_suffixes;
 }
index 6211deb3d0e27fe410854cd92ccfb60c8fc70f8a..1df5fd6f68e2e17ce119324d24b371c0230005d8 100644 (file)
--- a/ogg_afh.c
+++ b/ogg_afh.c
@@ -25,7 +25,6 @@
 #include "server.cmdline.h"
 #include "server.h"
 #include "vss.h"
-#include "afh.h"
 #include "error.h"
 #include "string.h"
 
 #define CHUNK_SIZE 32768
 static double chunk_time = 0.25;
 
-static OggVorbis_File *oggvorbis_file;
-static int header_len;
-static char *header;
-static ssize_t *chunk_table;
-static struct audio_format_handler *af;
+static size_t cb_read(void *buf, size_t size, size_t nmemb, void *datasource)
+{
+       FILE *f = datasource;
+       return fread(buf, size, nmemb, f);
+}
+
+static int cb_seek(__a_unused void *datasource, ogg_int64_t offset,
+               int whence)
+{
+       FILE *f = datasource;
+       return fseek(f, offset, whence);
+}
+
+/* don't do anything as vss still needs the open filehandle */
+static int cb_close(__a_unused void *datasource)
+{
+       return 0;
+}
+
+static long cb_tell(void *datasource)
+{
+       FILE *f = datasource;
+       return ftell(f);
+}
+
+static int ogg_open_callbacks(void *datasource, OggVorbis_File *vf, ov_callbacks c)
+{
+       int ret = ov_open_callbacks(datasource, vf,
+               NULL, /* no initial buffer */
+               0, /* no initial bytes */
+               c); /* the ov_open_callbacks */
+
+       /* FIXME: provide better error codes */
+       if (ret == OV_EREAD)
+               return -E_OGG_READ;
+       if (ret == OV_ENOTVORBIS)
+               return -E_OGG_READ;
+       if (ret == OV_EVERSION)
+               return -E_OGG_READ;
+       if (ret == OV_EBADHEADER)
+               return -E_OGG_READ;
+       if (ret < 0)
+               return -E_OGG_READ;
+       return 1;
+
+}
+
+static int ogg_save_header(FILE *file, struct audio_format_info *afi)
+{
+       int ret;
+
+       afi->header = para_malloc(afi->header_len);
+       rewind(file);
+       ret = read(fileno(file), afi->header, afi->header_len);
+       if (ret == afi->header_len)
+               return 1;
+       free(afi->header);
+       return -E_OGG_READ;
+}
 
-static int ogg_compute_header_len(FILE *file)
+static int ogg_compute_header_len(FILE *file, struct audio_format_info *afi)
 {
        int ret, len, in = fileno(file);
        unsigned int serial;
@@ -101,11 +154,11 @@ static int ogg_compute_header_len(FILE *file)
        ogg_stream_packetout(stream_in, &packet);
        ogg_stream_packetin(stream_out, &packet);
 
-       header_len = 0;
+       afi->header_len = 0;
        while (ogg_stream_flush(stream_out, &page))
-               header_len += page.body_len + page.header_len;
-       ret = len;
-       PARA_INFO_LOG("header_len = %d\n", header_len);
+               afi->header_len += page.body_len + page.header_len;
+       PARA_INFO_LOG("header_len = %d\n", afi->header_len);
+       ret = ogg_save_header(file, afi);
 err2:
        ogg_stream_destroy(stream_in);
        ogg_stream_destroy(stream_out);
@@ -116,37 +169,13 @@ err1:
        return ret;
 }
 
-static void tunetable(long unsigned num_chunks)
-{
-       int i = 1, j = -1, lp = 1;
-       while (i < num_chunks) {
-               if (chunk_table[i] == chunk_table[lp]) {
-                       i++;
-                       continue;
-               }
-               if (j < 0)
-                       tv_scale(i, &af->chunk_tv, &af->eof_tv);
-               for (j = lp; j < i; j++)
-                       chunk_table[j] = chunk_table[i];
-               lp = i;
-       }
-#if 1
-       for (i = 2; i < num_chunks; i++)
-               if (chunk_table[i] != chunk_table[1])
-                       break;
-       lp = i;
-       for (i = 2; i < num_chunks - lp; i++)
-               chunk_table[i] = chunk_table[i + lp];
-#endif
-}
-
-
 /*
  * Alloc and fill array table of byte offsets. chunk_table[i] is the
  * offset in the current input file at which the sample containing time i *
- * CHUNK_TIME begins.
+ * CHUNK_TIME begins. Always successful.
  */
-static long unsigned ogg_compute_chunk_table(double time_total)
+static long unsigned ogg_compute_chunk_table(OggVorbis_File *of,
+       struct audio_format_info *afi, double time_total)
 {
        int i, ret, num;
        ssize_t max_chunk_len, pos = 0, min = 0, old_pos;
@@ -157,135 +186,99 @@ static long unsigned ogg_compute_chunk_table(double time_total)
        num = time_total / chunk_time + 3;
        PARA_DEBUG_LOG("chunk time: %g allocating %d chunk pointers\n",
                chunk_time, num);
-       chunk_table = para_malloc(num * sizeof(size_t));
-       chunk_table[0] = 0;
+       afi->chunk_table = para_malloc(num * sizeof(size_t));
+       afi->chunk_table[0] = 0;
        max_chunk_len = 0;
        for (i = 1; ret == 0; i++) {
                ogg_int64_t diff;
-               ret = ov_time_seek(oggvorbis_file, i * chunk_time);
+               ret = ov_time_seek(of, i * chunk_time);
                if (ret)
                        break;
-               pos = ov_raw_tell(oggvorbis_file);
+               pos = ov_raw_tell(of);
                diff = pos - old_pos;
                max_chunk_len = PARA_MAX(max_chunk_len, diff);
                min = (i == 1)? diff : PARA_MIN(min, diff);
-               chunk_table[i] = pos;
-               if (i < 11 || !((i - 1) % 1000)|| i > num - 11)
-                       PARA_DEBUG_LOG("chunk #%d: %g secs, pos: %zd, "
-                               "size: %zd\n", i - 1,
-                               i * chunk_time, pos, pos - old_pos);
+               afi->chunk_table[i] = pos;
+//             if (i < 11 || !((i - 1) % 1000)|| i > num - 11)
+//                     PARA_DEBUG_LOG("chunk #%d: %g secs, pos: %zd, "
+//                             "size: %zd\n", i - 1,
+//                             i * chunk_time, pos, pos - old_pos);
                old_pos = pos;
        }
        num_chunks = i - 1;
-       chunk_table[i] = pos;
-       tunetable(num_chunks);
+       afi->chunk_table[i] = pos;
        PARA_INFO_LOG("%lu chunks (%fs), max chunk: %zd, min chunk: %zd\n",
                num_chunks, chunk_time, max_chunk_len, min);
        return num_chunks;
 }
 
-static void ogg_close_audio_file(void)
-{
-       if (oggvorbis_file) {
-               PARA_DEBUG_LOG("%s", "ov_clear\n");
-               ov_clear(oggvorbis_file);
-               free(oggvorbis_file);
-               oggvorbis_file = NULL;
-       }
-       free(header);
-       header = NULL;
-       header_len = 0;
-       free(chunk_table);
-       chunk_table = NULL;
-}
-
-static int ogg_save_header(FILE *file, int len)
-{
-       int ret;
-
-       header = para_malloc(len);
-       rewind(file);
-       ret = read(fileno(file), header, len);
-       if (ret != len)
-               return -E_OGG_READ;
-       return 1;
-}
-
 /*
  * Init oggvorbis file and write some tech data to given pointers.
  */
-static int ogg_get_file_info(FILE *file, char *info_str, long unsigned *frames,
-       int *seconds, size_t **vss_chunk_table)
+static int ogg_get_file_info(FILE *file, struct audio_format_info *afi)
 {
        int ret;
        double time_total;
        vorbis_info *vi;
        ogg_int64_t raw_total;
        long vi_sampling_rate, vi_bitrate;
+       OggVorbis_File of;
+       static const ov_callbacks ovc = {
+               .read_func = cb_read,
+               .seek_func = cb_seek,
+               .close_func = cb_close,
+               .tell_func = cb_tell
+       };
 
        if (!file)
                return -E_OGG_NO_FILE;
-       ret = ogg_compute_header_len(file);
-       if (ret < 0)
-               return ret;
-       ret = ogg_save_header(file, header_len);
+       ret = ogg_compute_header_len(file, afi);
        if (ret < 0)
                return ret;
        rewind(file);
-       oggvorbis_file = para_malloc(sizeof(OggVorbis_File));
-       ret = ov_open(file, oggvorbis_file, NULL, 0);
-       if (ret < 0) {
-               free(oggvorbis_file);
-               free(header);
-               return -E_OGG_OPEN;
-       }
+       ret = ogg_open_callbacks(file, &of, ovc);
+       if (ret < 0)
+               goto err;
        ret = -E_OGG_INFO;
-       vi = ov_info(oggvorbis_file, 0);
+       vi = ov_info(&of, 0);
        if (!vi)
                goto err;
-       time_total = ov_time_total(oggvorbis_file, -1);
-       raw_total = ov_raw_total(oggvorbis_file, -1);
-       *seconds = time_total;
+       time_total = ov_time_total(&of, -1);
+       raw_total = ov_raw_total(&of, -1);
+       afi->seconds_total = time_total;
        vi_sampling_rate = vi->rate;
-       vi_bitrate = ov_bitrate(oggvorbis_file, 0);
+       vi_bitrate = ov_bitrate(&of, 0);
        rewind(file);
-       *frames = ogg_compute_chunk_table(time_total);
+       afi->chunks_total = ogg_compute_chunk_table(&of, afi, time_total);
        rewind(file);
-       *vss_chunk_table = chunk_table;
-       sprintf(info_str, "audio_file_info1:%lu x %lu, %ldkHz, %d channels, %ldkbps\n"
+       sprintf(afi->info_string, "audio_file_info1:%lu x %lu, %ldkHz, "
+               "%d channels, %ldkbps\n"
                "audio_file_info2: \n"
                "audio_file_info3: \n",
-               *frames, (long unsigned) (chunk_time * 1000 * 1000),
+               afi->chunks_total, (long unsigned) (chunk_time * 1000 * 1000),
                vi_sampling_rate / 1000, vi->channels, vi_bitrate / 1000
                );
        rewind(file);
-       return 1;
+       afi->chunk_tv.tv_sec = 0;
+       afi->chunk_tv.tv_usec = 250 * 1000;
+       tv_scale(3, &afi->chunk_tv, &afi->eof_tv);
+       ret = 1;
 err:
-       ogg_close_audio_file();
+       ov_clear(&of); /* keeps the file open */
+       if (ret < 0)
+               free(afi->header);
        return ret;
 }
 
-static char *ogg_get_header_info(int *len)
-{
-       *len = header_len;
-       return header;
-}
-
 static const char* ogg_suffixes[] = {"ogg", NULL};
 
 /**
  * the init function of the ogg vorbis audio format handler
  *
- * \param p pointer to the struct to initialize
+ * \param afh pointer to the struct to initialize
  */
-void ogg_init(struct audio_format_handler *p)
+void ogg_init(struct audio_format_handler *afh)
 {
-       af = p;
-       af->get_file_info = ogg_get_file_info,
-       af->close_audio_file = ogg_close_audio_file;
-       af->get_header_info = ogg_get_header_info;
-       af->chunk_tv.tv_sec = 0;
-       af->chunk_tv.tv_usec = 250 * 1000;
-       tv_scale(3, &af->chunk_tv, &af->eof_tv);
-       af->suffixes = ogg_suffixes;
+       afh->get_file_info = ogg_get_file_info,
+       afh->suffixes = ogg_suffixes;
 }
index 41d9a2accd71076daddfe2c101634cc0945b4dfb..7e52fa5e12a2d929a1ef8e390ff31e5dcb7e6b64 100644 (file)
--- a/server.c
+++ b/server.c
@@ -369,6 +369,7 @@ static unsigned do_inits(int argc, char **argv)
        if (conf.daemon_given)
                daemon_init();
        init_selector();
+//     PARA_ERROR_LOG("num: %d\n", mmd->selector_num);
        PARA_NOTICE_LOG("%s", "initializing virtual streaming system\n");
        vss_init();
        mmd->server_pid = getpid();
index 9dee3e3495ae11f24412b2ab19ded2313ed2c16f..b33ba1dd806f91c027027e01099fb6a12fad06c6 100644 (file)
--- a/server.h
+++ b/server.h
@@ -19,6 +19,7 @@
 /** \file server.h common server data structures */
 
 #include "para.h"
+#include "afh.h"
 #include <openssl/pem.h>
 
 /** size of the selector_info and audio_file info strings of struct misc_meta_data */
@@ -72,7 +73,9 @@ struct sender_command_data{
  *     - The contents are listed in the stat command and have to be up to
  *     date.
  */
-struct misc_meta_data{
+struct misc_meta_data {
+/** information on the current audio file  */
+       struct audio_format_info afi;
 /** the size of the current audio file in bytes */
        long unsigned int size;
 /** the full path of the current audio file */
@@ -87,20 +90,14 @@ struct misc_meta_data{
        unsigned int new_vss_status_flags;
 /** the number of data chunks sent for the current audio file */
        long unsigned chunks_sent;
-/** the number of chunks this audio file contains */
-       long unsigned chunks_total;
 /** set by the jmp/ff commands to the new position in chunks */
        long unsigned repos_request;
 /** the number of the chunk currently sent out*/
        long unsigned current_chunk;
 /** the milliseconds that have been skipped of the current audio file */
        long offset;
-/** the length of the audio file in seconds */
-       int seconds_total;
 /** the time para_server started to stream */
        struct timeval stream_start;
-/** a string that gets filled in by the audio format handler */
-       char audio_file_info[MMD_INFO_SIZE];
 /** the event counter
  *
  * commands may increase this to force a status update to be sent to all
diff --git a/vss.c b/vss.c
index 9aeff44fd77e508d7c842a386a115ef5f72330cf..50c86ed7d8ef7069e6d9baea3df7d18c7e6ae3c2 100644 (file)
--- a/vss.c
+++ b/vss.c
@@ -26,7 +26,6 @@
 #include <sys/time.h> /* gettimeofday */
 #include "server.cmdline.h"
 #include "afs.h"
-#include "afh.h"
 #include "vss.h"
 #include "send.h"
 #include "error.h"
@@ -44,7 +43,7 @@ extern struct misc_meta_data *mmd;
 extern struct audio_file_selector selectors[];
 extern struct sender senders[];
 static char *inbuf;
-static size_t *chunk_table, inbuf_size;
+static size_t inbuf_size;
 
 static FILE *audio_file = NULL;
 
@@ -186,8 +185,7 @@ void vss_init(void)
 
 static int get_file_info(int i)
 {
-       return  afl[i].get_file_info(audio_file, mmd->audio_file_info,
-               &mmd->chunks_total, &mmd->seconds_total, &chunk_table);
+       return  afl[i].get_file_info(audio_file, &mmd->afi);
 }
 
 /**
@@ -261,7 +259,7 @@ static int update_mmd(void)
        return 1;
 }
 
-static void get_song(void)
+static void vss_get_audio_file(void)
 {
        char **sl = selectors[mmd->selector_num].get_audio_file_list(10);
        int i;
@@ -321,7 +319,7 @@ static void vss_next_chunk_time(struct timeval *due)
 {
        struct timeval tmp;
 
-       tv_scale(mmd->chunks_sent, &afl[mmd->audio_format].chunk_tv, &tmp);
+       tv_scale(mmd->chunks_sent, &mmd->afi.chunk_tv, &tmp);
        tv_add(&tmp, &mmd->stream_start, due);
 }
 
@@ -373,17 +371,21 @@ static void vss_eof(struct audio_format_handler *af)
                return;
        }
        gettimeofday(&now, NULL);
-       tv_add(&af->eof_tv, &now, &eof_barrier);
-       af->close_audio_file();
+       tv_add(&mmd->afi.eof_tv, &now, &eof_barrier);
+       fclose(audio_file);
        audio_file = NULL;
        mmd->audio_format = -1;
        af = NULL;
        mmd->chunks_sent = 0;
        mmd->offset = 0;
-       mmd->seconds_total = 0;
+       mmd->afi.seconds_total = 0;
+       free(mmd->afi.chunk_table);
+       mmd->afi.chunk_table = NULL;
+       free(mmd->afi.header);
+       mmd->afi.header = NULL;
        tmp  = make_message("%s:\n%s:\n%s:\n", status_item_list[SI_AUDIO_INFO1],
                status_item_list[SI_AUDIO_INFO2], status_item_list[SI_AUDIO_INFO3]);
-       strcpy(mmd->audio_file_info, tmp);
+       strcpy(mmd->afi.info_string, tmp);
        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]);
@@ -406,12 +408,10 @@ static void vss_eof(struct audio_format_handler *af)
  */
 char *vss_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);
+       *header_len = mmd->afi.header_len;
+       return mmd->afi.header;
 }
 
 /**
@@ -436,7 +436,7 @@ struct timeval *vss_chunk_time(void)
 {
        if (mmd->audio_format < 0)
                return NULL;
-       return &afl[mmd->audio_format].chunk_tv;
+       return &mmd->afi.chunk_tv;
 }
 
 /**
@@ -479,7 +479,7 @@ again:
                        struct timeval now;
                        gettimeofday(&now, NULL);
                        if (!vss_paused() || mmd->chunks_sent)
-                               tv_add(&af->eof_tv, &now, &eof_barrier);
+                               tv_add(&mmd->afi.eof_tv, &now, &eof_barrier);
                        if (vss_repos())
                                tv_add(&now, &announce_tv, &data_send_barrier);
                        if (mmd->new_vss_status_flags & VSS_NOMORE)
@@ -495,7 +495,7 @@ again:
        if (!ret && !audio_file && vss_playing() &&
                        !(mmd->new_vss_status_flags & VSS_NOMORE)) {
                PARA_DEBUG_LOG("%s", "ready and playing, but no audio file\n");
-               get_song();
+               vss_get_audio_file();
                goto again;
        }
        return ret;
@@ -504,12 +504,10 @@ again:
 /**
  * read a chunk of data from the current audio file
  *
- * \param current_chunk the chunk number to read
- *
  * \return The length of the chunk on success, zero on end of file, negative on
  * errors.  Note: If the current chunk is of length zero, but the end of the
  * file is not yet reached, this function returns -E_EMPTY_CHUNK.
- * */
+ */
 ssize_t vss_read_chunk(void)
 {
        ssize_t len;
@@ -517,15 +515,15 @@ ssize_t vss_read_chunk(void)
        int ret;
        long unsigned cc = mmd->current_chunk;
 
-       if (cc >= mmd->chunks_total) /* eof */
+       if (cc >= mmd->afi.chunks_total) /* eof */
                return 0;
-       len = chunk_table[cc + 1] - chunk_table[cc];
+       len = mmd->afi.chunk_table[cc + 1] - mmd->afi.chunk_table[cc];
        if (!len) /* nothing to send for this run */
                return -E_EMPTY_CHUNK;
-       pos = chunk_table[cc];
+       pos = mmd->afi.chunk_table[cc];
        if (inbuf_size < len) {
                PARA_INFO_LOG("increasing inbuf for chunk #%lu/%lu to %zu bytes\n",
-                       cc, mmd->chunks_total, len);
+                       cc, mmd->afi.chunks_total, len);
                inbuf = para_realloc(inbuf, len);
                inbuf_size = len;
        }
@@ -543,9 +541,6 @@ ssize_t vss_read_chunk(void)
  * the current audio format handler to obtain a pointer to the data to be
  * sent out as well as its length. This information is then passed to each
  * supported sender's send() function which does the actual sending.
- *
- * Return value: Positive return value on success, zero on eof and negative
- * on errors.
  */
 void vss_send_chunk(void)
 {
@@ -586,7 +581,7 @@ void vss_send_chunk(void)
        if (!mmd->chunks_sent) {
                struct timeval tmp;
                gettimeofday(&mmd->stream_start, NULL);
-               tv_scale(mmd->current_chunk, &af->chunk_tv, &tmp);
+               tv_scale(mmd->current_chunk, &mmd->afi.chunk_tv, &tmp);
                mmd->offset = tv2ms(&tmp);
                mmd->events++;
        }