Merge /fml/ag-raetsch/home/maan/scm/paraslash_meins/paraslash
authorAndre Noll <maan@systemlinux.org>
Mon, 26 Mar 2007 12:51:03 +0000 (14:51 +0200)
committerAndre Noll <maan@systemlinux.org>
Mon, 26 Mar 2007 12:51:03 +0000 (14:51 +0200)
Conflicts:

mp3_afh.c

Fix the conflict and add more detailed error message to para_mmap().

NEWS
aac_afh.c
afh.h
fd.c
mp3_afh.c
mysql_selector.c
ogg_afh.c
vss.c

diff --git a/NEWS b/NEWS
index 58c3722..9277d1c 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -10,8 +10,9 @@ cleanup which removes some similar/duplicate code and makes it easier
 to implement plugins for other audio formats. Of course, the usual mix
 of other improvements/changes/bugfixes also made it into the release.
 
-       - simplified audio format handlers (some of the handling functions
+       - simplified audio format handlers (most of the handling functions
          were moved one layer up to the virtual streaming system).
+       - para_server uses mmap to read audio files
        - repositioning of mp3 streams is much faster, in particular for
          jumping near the end of large mp3 files.
        - permission flags DB_READ,DB_WRITE have been renamed to AFS_READ
index bf402f0..e9417d2 100644 (file)
--- a/aac_afh.c
+++ b/aac_afh.c
 
 /** \file aac_afh.c para_server's aac audio format handler */
 
-#include "server.cmdline.h"
 #include "server.h"
-#include "vss.h"
 #include "error.h"
 #include "string.h"
 #include "aac.h"
-#include "fd.h"
 
 static int aac_find_stsz(unsigned char *buf, off_t buflen, off_t *skip)
 {
@@ -91,7 +88,7 @@ static long unsigned aac_set_chunk_tv(struct audio_format_info *afi,
        PARA_INFO_LOG("%luHz, %fs (%lu x %lums)\n",
                mp4ASC->samplingFrequency, ms / 1000,
                afi->chunks_total, tv2ms(&afi->chunk_tv));
-       return ms / 1000;
+       return ms < 1000? -E_MP4ASC : ms / 1000;
 }
 
 /*
@@ -116,10 +113,14 @@ static int aac_get_file_info(char *map, off_t numbytes,
        ret = -E_AACDEC_INIT;
        if (NeAACDecInit(handle, map + skip, decoder_len, &rate, &channels))
                goto out;
+       if (!channels)
+               goto out;
        PARA_INFO_LOG("rate: %lu, channels: %d\n", rate, channels);
        ret = -E_MP4ASC;
        if (NeAACDecAudioSpecificConfig(map + skip, numbytes - skip, &mp4ASC))
                goto out;
+       if (!mp4ASC.samplingFrequency)
+               goto out;
        ret = aac_compute_chunk_table(afi, map, numbytes);
        if (ret < 0)
                goto out;
@@ -131,11 +132,18 @@ static int aac_get_file_info(char *map, off_t numbytes,
        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"
+       afi->channels = channels;
+       afi->frequency = rate;
+       ret = (afi->chunk_table[afi->chunks_total] - afi->chunk_table[0]) * 8; /* bits */
+       ret += (channels * afi->seconds_total * 500); /* avoid rounding error */
+       afi->bitrate = ret / (channels * afi->seconds_total * 1000);
+       sprintf(afi->info_string, "audio_file_info1:%lu x %lums, "
+               "%uHz, %d channel%s, %ukb/s\n"
                "audio_file_info2:\n"
                "audio_file_info3:\n",
-               afi->chunks_total,
-               tv2ms(&afi->chunk_tv));
+               afi->chunks_total, tv2ms(&afi->chunk_tv),
+               afi->frequency, channels, channels == 1? "" : "s", afi->bitrate
+       );
        tv_scale(20, &afi->chunk_tv, &afi->eof_tv);
        ret = 1;
 out:
diff --git a/afh.h b/afh.h
index 246cb92..38e1ff0 100644 (file)
--- a/afh.h
+++ b/afh.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005-2006 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 2005-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
@@ -61,17 +61,21 @@ struct audio_format_info {
        /** 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 */
+        * The header is needed by senders in case a new client connects in the
+        * middle of the stream. The length of the header defaults to zero
+        * which means that this audio format does not need any special header
+        * treatment. The audio format handler does not need to set this to
+        * zero in this case.
+        */
        unsigned header_len;
+       /**
+        * The position of the header within the audio file. Ignored if \a
+        * header_len equals zero.
+        */
+       unsigned header_offset;
+       uint8_t channels;
+       uint16_t frequency;
+       uint16_t bitrate;
 };
 
 /**
diff --git a/fd.c b/fd.c
index 1116f9e..db1825c 100644 (file)
--- a/fd.c
+++ b/fd.c
@@ -163,7 +163,9 @@ void *para_mmap(size_t length, int prot, int flags, int fd, off_t offset)
        void *ret = mmap(NULL, length, prot, flags, fd, offset);
        if (ret != MAP_FAILED)
                return ret;
-       PARA_EMERG_LOG("mmap failed: %s", strerror(errno));
+       PARA_EMERG_LOG("mmap failed: %s\n", strerror(errno));
+       PARA_EMERG_LOG("length: %zu, flags: %d, fd: %d, offset: %zu\n",
+               length, flags, fd, offset);
        exit(EXIT_FAILURE);
 }
 
index 0c8efbd..9ef5dff 100644 (file)
--- a/mp3_afh.c
+++ b/mp3_afh.c
  *                      Johannes Overmann <overmann@iname.com>
  */
 
-#include "server.cmdline.h"
 #include "server.h"
-#include "vss.h"
 #include "error.h"
-#include "fd.h"
 #include "string.h"
 
 /** \cond some defines and structs which are only used in this file */
@@ -72,8 +69,6 @@ struct mp3info {
        int id3_isvalid;
        struct id3tag id3;
        int vbr;
-       long unsigned br_average;
-       int freq;
 };
 
 /** \endcond */
@@ -116,6 +111,15 @@ static const char *header_mode(struct mp3header *h)
        return mode_text[h->mode];
 }
 
+static int header_channels(struct mp3header *h)
+{
+       if (h->mode > 3)
+               return 0;
+       if (h->mode < 3)
+               return 2;
+       return 1;
+}
+
 static int header_bitrate(struct mp3header *h)
 {
        if (!h->layer || h->layer > 3 || h->bitrate > 14 || !h->bitrate)
@@ -144,14 +148,14 @@ static void write_info_str(struct audio_format_info *afi)
        int v = mp3.id3_isvalid;
 
        snprintf(afi->info_string, MMD_INFO_SIZE,
-               "audio_file_info1:%lu x %lums, %lu kbit/s (%cbr) %i KHz %s\n"
+               "audio_file_info1:%lu x %lums, %u kbit/s (%cbr) %i KHz %s\n"
                "audio_file_info2:%s, by %s\n"
                "audio_file_info3:A: %s, Y: %s, C: %s\n",
                afi->chunks_total,
                tv2ms(&afi->chunk_tv),
-               mp3.br_average,
+               afi->bitrate,
                mp3.vbr? 'v' : 'c',
-               mp3.freq / 1000,
+               afi->frequency / 1000,
                header_mode(&mp3.header),
                v && *mp3.id3.title? mp3.id3.title : "(title tag not set)",
                v && *mp3.id3.artist? mp3.id3.artist : "(artist tag not set)",
@@ -335,7 +339,6 @@ static int mp3_read_info(unsigned char *map, off_t numbytes,
        mp3_get_id3(map, numbytes, &fpos);
        fpos = 0;
        mp3.vbr = 0;
-       mp3.freq = 0;
        while (1) {
                int freq, br, fl;
                struct timeval tmp, cct; /* current chunk time */
@@ -382,8 +385,9 @@ static int mp3_read_info(unsigned char *map, off_t numbytes,
        if (!afi->chunks_total || !freq_avg || !br_avg)
                goto err_out;
        afi->chunk_table[afi->chunks_total] = numbytes - 1;
-       mp3.br_average = br_avg;
-       mp3.freq = freq_avg;
+       afi->bitrate = br_avg;
+       afi->frequency = freq_avg;
+       afi->channels = header_channels(&mp3.header);
        afi->seconds_total = (tv2ms(&total_time) + 500) / 1000;
        tv_divide(afi->chunks_total, &total_time, &afi->chunk_tv);
        PARA_DEBUG_LOG("%lu chunks, each %lums\n", afi->chunks_total,
index d7d4ee1..b2a925e 100644 (file)
@@ -900,7 +900,6 @@ write:
        return info;
 }
 
-
 /* might return NULL */
 static char *get_current_audio_file(void)
 {
@@ -911,6 +910,29 @@ static char *get_current_audio_file(void)
        return name;
 }
 
+/* If called as child, mmd_lock must be held */
+static void update_mmd(char *info)
+{
+       PARA_DEBUG_LOG("%s", "updating shared memory area\n");
+       strncpy(mmd->selector_info, info, MMD_INFO_SIZE - 1);
+       mmd->selector_info[MMD_INFO_SIZE - 1] = '\0';
+}
+
+static void refresh_selector_info(void)
+{
+       char *name = get_current_audio_file();
+       char *info;
+
+       if (!name)
+               return;
+       info = get_selector_info(name);
+       free(name);
+       mmd_lock();
+       update_mmd(info);
+       mmd_unlock();
+       free(info);
+}
+
 /* list attributes / print database info */
 static int com_la_info(int fd, int argc, char *argv[])
 {
@@ -1186,7 +1208,10 @@ int com_picass(int fd, int argc, char *argv[])
  */
 int com_snp(int fd, int argc, char *argv[])
 {
-       return com_set(fd, argc, argv);
+       int ret = com_set(fd, argc, argv);
+       if (ret >= 0)
+               refresh_selector_info();
+       return ret;
 }
 
 /*
@@ -1463,14 +1488,6 @@ out:
        return ret;
 }
 
-/* If called as child, mmd_lock must be held */
-static void update_mmd(char *info)
-{
-       PARA_DEBUG_LOG("%s", "updating shared memory area\n");
-       strncpy(mmd->selector_info, info, MMD_INFO_SIZE - 1);
-       mmd->selector_info[MMD_INFO_SIZE - 1] = '\0';
-}
-
 static void update_audio_file_server_handler(char *name)
 {
        char *info;
@@ -1492,24 +1509,11 @@ int com_us(__a_unused int fd, int argc, char *argv[])
                return -E_ESCAPE;
        ret = update_audio_file(argv[1]);
        free(tmp);
+       if (ret >= 0)
+               refresh_selector_info();
        return ret;
 }
 
-static void refresh_selector_info(void)
-{
-       char *name = get_current_audio_file();
-       char *info;
-
-       if (!name)
-               return;
-       info = get_selector_info(name);
-       free(name);
-       mmd_lock();
-       update_mmd(info);
-       mmd_unlock();
-       free(info);
-}
-
 /* select previous / next stream */
 static int com_ps_ns(__a_unused int fd, int argc, char *argv[])
 {
index eaed162..5adcc25 100644 (file)
--- a/ogg_afh.c
+++ b/ogg_afh.c
@@ -22,9 +22,7 @@
 #include <vorbis/codec.h>
 #include <vorbis/vorbisfile.h>
 
-#include "server.cmdline.h"
 #include "server.h"
-#include "vss.h"
 #include "error.h"
 #include "string.h"
 
@@ -119,12 +117,6 @@ static int ogg_open_callbacks(void *datasource, OggVorbis_File *vf, ov_callbacks
 
 }
 
-static void ogg_save_header(char *map, struct audio_format_info *afi)
-{
-       afi->header = para_malloc(afi->header_len);
-       memcpy(afi->header, map, afi->header_len);
-}
-
 static int ogg_compute_header_len(char *map, off_t numbytes,
                struct audio_format_info *afi)
 {
@@ -189,7 +181,7 @@ static int ogg_compute_header_len(char *map, off_t numbytes,
        while (ogg_stream_flush(stream_out, &page))
                afi->header_len += page.body_len + page.header_len;
        PARA_INFO_LOG("header_len = %d\n", afi->header_len);
-       ogg_save_header(map, afi);
+       afi->header_offset = 0;
        ret = 1;
 err2:
        ogg_stream_destroy(stream_in);
@@ -218,10 +210,10 @@ static long unsigned ogg_compute_chunk_table(OggVorbis_File *of,
        num = time_total / chunk_time + 3;
        PARA_DEBUG_LOG("chunk time: %g allocating %d chunk pointers\n",
                chunk_time, num);
-       afi->chunk_table = para_malloc(num * sizeof(size_t));
+       afi->chunk_table = para_malloc((num + 1) * sizeof(size_t));
        afi->chunk_table[0] = 0;
        max_chunk_len = 0;
-       for (i = 1; ret == 0; i++) {
+       for (i = 1; ret <= num; i++) {
                ogg_int64_t diff;
                ret = ov_time_seek(of, i * chunk_time);
                if (ret)
@@ -238,7 +230,7 @@ static long unsigned ogg_compute_chunk_table(OggVorbis_File *of,
                old_pos = pos;
        }
        num_chunks = i - 1;
-       afi->chunk_table[i] = pos;
+//fi->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;
@@ -251,10 +243,7 @@ static int ogg_get_file_info(char *map, off_t numbytes,
                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;
        const ov_callbacks ovc = {
                .read_func = cb_read,
@@ -274,18 +263,17 @@ static int ogg_get_file_info(char *map, off_t numbytes,
        vi = ov_info(&of, 0);
        if (!vi)
                goto err;
-       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(&of, 0);
-       afi->chunks_total = ogg_compute_chunk_table(&of, afi, time_total);
-       sprintf(afi->info_string, "audio_file_info1:%lu x %lu, %ldkHz, "
-               "%d channels, %ldkbps\n"
+       afi->seconds_total = ov_time_total(&of, -1);
+       afi->frequency = vi->rate;
+       afi->bitrate = ov_bitrate(&of, 0);
+       afi->channels = vi->channels;
+       afi->chunks_total = ogg_compute_chunk_table(&of, afi, afi->seconds_total);
+       sprintf(afi->info_string, "audio_file_info1:%lu x %lu, %ukHz, "
+               "%d channels, %ukbps\n"
                "audio_file_info2: \n"
                "audio_file_info3: \n",
                afi->chunks_total, (long unsigned) (chunk_time * 1000 * 1000),
-               vi_sampling_rate / 1000, vi->channels, vi_bitrate / 1000
+               afi->frequency / 1000, vi->channels, afi->bitrate / 1000
                );
        afi->chunk_tv.tv_sec = 0;
        afi->chunk_tv.tv_usec = 250 * 1000;
@@ -293,8 +281,6 @@ static int ogg_get_file_info(char *map, off_t numbytes,
        ret = 1;
 err:
        ov_clear(&of); /* keeps the file open */
-       if (ret < 0)
-               free(afi->header);
        return ret;
 }
 
diff --git a/vss.c b/vss.c
index cb2d16c..a3c2e65 100644 (file)
--- a/vss.c
+++ b/vss.c
@@ -278,6 +278,7 @@ static void vss_get_audio_file(void)
                map = para_mmap(file_status.st_size, PROT_READ, MAP_PRIVATE,
                        audio_file, 0);
                strcpy(mmd->filename, sl[i]);
+               mmd->afi.header_len = 0; /* default: no header */
                if (update_mmd() < 0) { /* invalid file */
                        close(audio_file);
                        munmap(map, mmd->size);
@@ -384,8 +385,6 @@ static void vss_eof(void)
        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->afi.info_string, tmp);
@@ -411,10 +410,10 @@ static void vss_eof(void)
  */
 char *vss_get_header(int *header_len)
 {
-       if (mmd->audio_format < 0)
+       if (mmd->audio_format < 0 || !map || !mmd->afi.header_len)
                return NULL;
        *header_len = mmd->afi.header_len;
-       return mmd->afi.header;
+       return map + mmd->afi.header_offset;
 }
 
 /**