]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Add Infrastructure for dynamic header computation.
authorAndre Noll <maan@systemlinux.org>
Sun, 3 Oct 2010 11:07:42 +0000 (13:07 +0200)
committerAndre Noll <maan@systemlinux.org>
Sat, 29 Jan 2011 10:43:33 +0000 (11:43 +0100)
vorbis allows to add arbitrary many comments to an audio file. These
comments are stored in ogg packet #2, which is part of the audio file
header of ogg vorbis files. Hence ogg/vorbis headers may be arbitrary
large. Since the header is sent periodically, this wastes bandwidth
and may cause FEC parameters to become unnecessary large.

This introductory patch paves the way for replacing ogg packet #2 at
stream time by a dummy packet with does not contain any comments and
is therefore of bounded size.

In order to do so, we need audio file headers which are not necessarily
an unmodified portion of the audio file. Therefore we call back into
the audio format handler code at stream time to compute an appropriate
audio file header.  Hence an optional new method ->get_header() is
added to struct audio_format_hander. If it is non-NULL, is is called
instead of using the first header_len bytes of the file.

Unfortunately, this implies that the virtual streaming system must
be aware of the audio format id in order to know which get_header()
method should be called. Thus we store the audio format id in struct
audio_file_data which is passed from the afs process to the server
process. Vss then calls afh_get_header() with the audio format id as
an additional argument.

ATM, the new functionality is not yet used as as no audio format
handler defines ->get_header() yet.

afh.c
afh.h
afh_common.c
afs.h
aft.c
vss.c

diff --git a/afh.c b/afh.c
index b5fb65fc418a6e4a3febef87cdce6d630b81cfb3..c5d7aec296a7a44b2fedfd2532ad838f89654e6c 100644 (file)
--- a/afh.c
+++ b/afh.c
@@ -83,15 +83,16 @@ static void print_chunk_table(struct afh_info *afhi)
        }
 }
 
-static int cat_file(void *audio_file_data, struct afh_info *afhi)
+static int cat_file(struct afh_info *afhi, int audio_format_id,
+               void *audio_file_data, size_t audio_file_size)
 {
        int ret;
        struct timeval stream_start;
        long unsigned i, first_chunk, last_chunk;
        const char *buf;
+       char *header;
        size_t size;
 
-
        if (conf.begin_chunk_arg < 0) {
                if (-conf.begin_chunk_arg > afhi->chunks_total)
                        return -ERRNO_TO_PARA_ERROR(EINVAL);
@@ -114,14 +115,18 @@ static int cat_file(void *audio_file_data, struct afh_info *afhi)
                return -ERRNO_TO_PARA_ERROR(EINVAL);
        if (!afhi->chunks_total)
                return 1;
-       afh_get_header(afhi, audio_file_data, &buf, &size);
-       if (size && first_chunk && !conf.no_header_given) {
-               PARA_INFO_LOG("writing audio file header (%zu bytes)\n", size);
-               ret = write(STDOUT_FILENO, buf, size);
-               if (ret < 0)
-                       return ret;
-               if (ret != size)
-                       return -E_AFH_SHORT_WRITE;
+       if (first_chunk > 0 && !conf.no_header_given) {
+               afh_get_header(afhi, audio_format_id, audio_file_data, audio_file_size,
+                       &header, &size);
+               if (size > 0) {
+                       PARA_INFO_LOG("writing header (%zu bytes)\n", size);
+                       ret = write(STDOUT_FILENO, header, size); /* FIXME */
+                       afh_free_header(header, audio_format_id);
+                       if (ret < 0)
+                               return ret;
+                       if (ret != size)
+                               return -E_AFH_SHORT_WRITE;
+               }
        }
        PARA_NOTICE_LOG("writing chunks %lu - %lu\n", first_chunk, last_chunk);
        gettimeofday(&stream_start, NULL);
@@ -184,9 +189,11 @@ int main(int argc, char **argv)
                        fd, &afhi);
                if (ret < 0)
                        goto out;
+
                audio_format_num = ret;
                if (conf.stream_given)
-                       ret = cat_file(audio_file_data, &afhi);
+                       ret = cat_file(&afhi, audio_format_num,
+                               audio_file_data, audio_file_size);
                else {
                        printf("File %d: %s\n", i + 1, conf.inputs[i]);
                        print_info(audio_format_num, &afhi);
diff --git a/afh.h b/afh.h
index 494a4e15adaf41bb10619b62c36a6a8a33a78fb4..8b747f8a436b0da18f3cd83a8e90c50e23e7ea83 100644 (file)
--- a/afh.h
+++ b/afh.h
@@ -90,6 +90,8 @@ struct audio_format_handler {
         */
        int (*get_file_info)(char *map, size_t numbytes, int fd,
                struct afh_info *afi);
+
+       void (*get_header)(void *map, size_t mapsize, char **buf, size_t *len);
 };
 
 void afh_init(void);
@@ -99,4 +101,7 @@ int compute_afhi(const char *path, char *data, size_t size,
 const char *audio_format_name(int);
 void afh_get_chunk(long unsigned chunk_num, struct afh_info *afhi,
                void *map, const char **buf, size_t *len);
-void afh_get_header(struct afh_info *afhi, 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, uint8_t audio_format_id,
+               void *map, size_t mapsize, char **buf, size_t *len);
+void afh_free_header(char *header_buf, uint8_t audio_format_id);
index 10376ba68feb8567291ef0c7325bb3af9c293713..7ecab4e47a9bd7e47bcc7e378043d62d663cf343 100644 (file)
@@ -248,21 +248,52 @@ void afh_get_chunk(long unsigned chunk_num, struct afh_info *afhi,
  * Get the header of an audio file.
  *
  * \param afhi The audio file handler data describing the file.
+ * \param audio_format_id Determines the audio format handler.
  * \param map The data of the audio file.
+ * \param mapsize The amount of bytes of the mmapped audio file.
  * \param buf The length of the header is stored here.
  * \param len Points to a buffer containing the header on return.
  *
  * 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 treatment.
+ *
+ * Otherwise, it is checked whether the audio format handler given by
+ * \a audio_format_id defines a ->get_header() method. If it does, this
+ * method is called to obtain the header. If ->get_header() is \p NULL,
+ * a reference to the first chunk of the audio file is returned.
+ *
+ * Once the header is no longer needed, the caller must call \ref
+ * afh_free_header() to free the resources allocated by this function.
  */
-void afh_get_header(struct afh_info *afhi, void *map, const char **buf, size_t *len)
+void afh_get_header(struct afh_info *afhi, uint8_t audio_format_id,
+               void *map, size_t mapsize, char **buf, size_t *len)
 {
+       struct audio_format_handler *afh = afl + audio_format_id;
+
        if (!map || !afhi || !afhi->header_len) {
                *buf = NULL;
                *len = 0;
                return;
        }
-       *len = afhi->header_len;
-       *buf = map;
+       if (!afh->get_header) {
+               *len = afhi->header_len;
+               *buf = map;
+               return;
+       }
+       afh->get_header(map, mapsize, buf, len);
+}
+
+/**
+ * Deallocate any resources obtained from afh_get_header().
+ *
+ * \param header_buf Pointer obtained via afh_get_header().
+ * \param audio_format_id Determines the audio format handler.
+ */
+void afh_free_header(char *header_buf, uint8_t audio_format_id)
+{
+       struct audio_format_handler *afh = afl + audio_format_id;
+
+       if (afh->get_header)
+               free(header_buf);
 }
diff --git a/afs.h b/afs.h
index cd98a9f86129405ba79fa02988791469bea712bb..96da2da027cf27268c7b5ad1b4af6755b593f7e6 100644 (file)
--- a/afs.h
+++ b/afs.h
@@ -131,6 +131,8 @@ struct audio_file_data {
        struct afh_info afhi;
        /** Size of the largest chunk. */
        uint32_t max_chunk_size;
+       /** Needed to get the audio file header. */
+       uint8_t audio_format_id;
 };
 
 /**
diff --git a/aft.c b/aft.c
index 9f39d705620ee5b3b0e5e784b099730b078350e9..266188b5b370a3e7e3e8aaa092ca093aca7c6c04 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -1124,6 +1124,7 @@ int open_and_update_audio_file(struct osl_row *aft_row, long score,
        new_afsi.last_played = time(NULL);
        save_afsi(&new_afsi, &afsi_obj); /* in-place update */
 
+       afd->audio_format_id = old_afsi.audio_format_id;
        load_chunk_table(&afd->afhi, chunk_table_obj.data);
        ret = make_status_items(afd, &old_afsi, path, score, file_hash);
        if (ret < 0)
diff --git a/vss.c b/vss.c
index 21ac37470e4748ea407fd7bacb96dfb42f3ee55a..8b3745218fe057bd237eb85b1d3e89d39275ae06 100644 (file)
--- a/vss.c
+++ b/vss.c
@@ -86,7 +86,7 @@ struct vss_task {
        /** Used by the scheduler. */
        struct task task;
        /** Pointer to the header of the mapped audio file. */
-       const char *header_buf;
+       char *header_buf;
        /** Length of the audio file header. */
        size_t header_len;
        /** Time between audio file headers are sent. */
@@ -807,6 +807,8 @@ static void vss_eof(struct vss_task *vsst)
        if (mmd->new_vss_status_flags & VSS_NOMORE)
                mmd->new_vss_status_flags = VSS_NEXT;
        set_eof_barrier(vsst);
+       afh_free_header(vsst->header_buf, mmd->afd.audio_format_id);
+       vsst->header_buf = NULL;
        para_munmap(vsst->map, mmd->size);
        vsst->map = NULL;
        mmd->chunks_sent = 0;
@@ -985,8 +987,8 @@ static void recv_afs_result(struct vss_task *vsst, fd_set *rfds)
        mmd->events++;
        mmd->num_played++;
        mmd->new_vss_status_flags &= (~VSS_NEXT);
-       afh_get_header(&mmd->afd.afhi, vsst->map, &vsst->header_buf,
-               &vsst->header_len);
+       afh_get_header(&mmd->afd.afhi, mmd->afd.audio_format_id,
+               vsst->map, mmd->size, &vsst->header_buf, &vsst->header_len);
        return;
 err:
        free(mmd->afd.afhi.chunk_table);