afh: Constify definition of audio format handlers.
authorAndre Noll <maan@tuebingen.mpg.de>
Tue, 25 Sep 2018 19:41:20 +0000 (21:41 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Fri, 21 Dec 2018 13:40:42 +0000 (14:40 +0100)
The audio_format_handler structure contains only pointers, and the
->init method of each instance initializes these pointers to constant
values.  The ->init() method is thus useless at best, and it prevents
the structures from being declared constant.

This patch removes ->init() of struct audio_format_handler and the
public afh_init() which iterates over all audio formats to call each
->init() method. The audio format handlers are modified to define an
instance of the structure rather than an init function which fills the
fields of the given structure. The structure can be declared constant,
but not static because afh_common.c needs a way to refer to it.

We rely on weak symbols to deal with audio format handlers which are
not compiled in. The codec-independent code in afh_common.c defines
a weak instance of the audio_format_handler structure for each audio
format. The command handlers which are compiled in override the weak
symbol with their own definition.

The afh receiver used to define afh_init() as its (receiver!) init
function, which no longer exists. Since receiver init functions are
optional, we don't need to supply a replacement. However, play.c
calls ->init() of the afh_receiver unconditionally. This call needs
to be removed to avoid a null pointer dereference.

13 files changed:
aac_afh.c
afh.c
afh.h
afh_common.c
afh_recv.c
flac_afh.c
mp3_afh.c
ogg_afh.c
opus_afh.c
play.c
server.c
spx_afh.c
wma_afh.c

index 3315a42..7f2a22a 100644 (file)
--- a/aac_afh.c
+++ b/aac_afh.c
@@ -333,17 +333,17 @@ close:
 }
 
 static const char * const aac_suffixes[] = {"m4a", "mp4", NULL};
+
 /**
- * the init function of the aac audio format handler
+ * The audio format handler for the Advanced Audio Codec.
  *
- * \param afh pointer to the struct to initialize
+ * This is only compiled in if the faad library is installed.
  */
-void aac_afh_init(struct audio_format_handler *afh)
-{
-       afh->get_file_info = aac_get_file_info,
-       afh->suffixes = aac_suffixes;
-       afh->rewrite_tags = aac_afh_rewrite_tags;
-       afh->open = aac_afh_open;
-       afh->get_chunk = aac_afh_get_chunk;
-       afh->close = aac_afh_close;
-}
+const struct audio_format_handler aac_afh = {
+       .get_file_info = aac_get_file_info,
+       .suffixes = aac_suffixes,
+       .rewrite_tags = aac_afh_rewrite_tags,
+       .open = aac_afh_open,
+       .get_chunk = aac_afh_get_chunk,
+       .close = aac_afh_close,
+};
diff --git a/afh.c b/afh.c
index aa6570e..69b834d 100644 (file)
--- a/afh.c
+++ b/afh.c
@@ -203,7 +203,6 @@ int main(int argc, char **argv)
        loglevel = OPT_UINT32_VAL(LOGLEVEL);
        version_handle_flag("afh", OPT_GIVEN(VERSION));
        handle_help_flags();
-       afh_init();
        for (i = 0; i < lls_num_inputs(lpr); i++) {
                int ret2;
                const char *path = lls_input(i, lpr);
diff --git a/afh.h b/afh.h
index eb53923..881db3c 100644 (file)
--- a/afh.h
+++ b/afh.h
@@ -80,12 +80,6 @@ struct audio_file_data {
  * in the other part of this struct.
  */
 struct audio_format_handler {
-       /**
-        * Pointer to the audio format handler's init function.
-        *
-        * Must initialize all function pointers and is assumed to succeed.
-        */
-       void (*init)(struct audio_format_handler*);
        /** Typical file endings for files that can be handled by this afh. */
        const char * const *suffixes;
        /**
@@ -133,7 +127,6 @@ struct audio_format_handler {
                int output_fd, const char *filename);
 };
 
-void afh_init(void);
 int guess_audio_format(const char *name);
 int compute_afhi(const char *path, char *data, size_t size,
        int fd, struct afh_info *afhi);
index fb4759a..a267f58 100644 (file)
 #include "string.h"
 #include "afh.h"
 
-typedef void afh_init_func(struct audio_format_handler *);
-
-/*
- * Declaration of the audio format handler init functions.
- *
- * These symbols are referenced in the afl array below.
- *
- * Most audio format handlers depend on an external library and are not
- * compiled in if the library is not installed. Hence it is well possible that
- * not all of these functions are defined. It does not hurt to declare them
- * anyway, and this avoids another set of ifdefs.
- */
-extern afh_init_func mp3_afh_init, ogg_afh_init, aac_afh_init, wma_afh_init,
-       spx_afh_init, flac_afh_init, opus_afh_init;
-
 /** The list of all status items */
 const char *status_item_list[] = {STATUS_ITEMS};
 
@@ -44,50 +29,21 @@ const char *status_item_list[] = {STATUS_ITEMS};
        AUDIO_FORMAT(flac) \
        AUDIO_FORMAT(opus) \
 
+/** \cond audio_format_handler */
 #define AUDIO_FORMAT(_fmt) #_fmt,
 static const char * const audio_format_names[] = {ALL_AUDIO_FORMATS};
 #undef AUDIO_FORMAT
-
-/*
- * It can be detected whether an audio format is compiled in by checking if the
- * init function pointer is NULL.
- */
-static struct audio_format_handler afl[] = {
-       {
-               .init = mp3_afh_init,
-       },
-       {
-#if defined(HAVE_OGG) && defined(HAVE_VORBIS)
-               .init = ogg_afh_init,
-#endif
-       },
-       {
-#if defined(HAVE_FAAD)
-               .init = aac_afh_init,
-#endif
-       },
-       {
-               .init = wma_afh_init,
-       },
-       {
-#if defined(HAVE_OGG) && defined(HAVE_SPEEX)
-               .init = spx_afh_init,
-#endif
-       },
-       {
-#if defined(HAVE_OGG) && defined(HAVE_FLAC)
-               .init = flac_afh_init,
-#endif
-       },
-       {
-#if defined(HAVE_OGG) && defined(HAVE_OPUS)
-               .init = opus_afh_init,
-#endif
-       },
-};
-
-/** This includes audio formats not compiled in. */
+/* Weak declarations must be public. */
+#define AUDIO_FORMAT(_fmt) \
+       struct audio_format_handler _fmt ## _afh __attribute__ ((weak)) \
+       = {.get_file_info = NULL};
+ALL_AUDIO_FORMATS
+#undef AUDIO_FORMAT
+#define AUDIO_FORMAT(_fmt) & _fmt ## _afh,
+static struct audio_format_handler *afl[] = {ALL_AUDIO_FORMATS};
+#undef AUDIO_FORMAT
 #define NUM_AUDIO_FORMATS (ARRAY_SIZE(afl))
+/** \endcond audio_format_handler */
 
 /**
  * Get the name of the given audio format.
@@ -110,7 +66,7 @@ static inline int next_audio_format(int format)
                format++;
                if (format >= NUM_AUDIO_FORMATS)
                        return format;
-               if (afl[format].init)
+               if (afl[format]->get_file_info)
                        return format;
        }
 }
@@ -120,21 +76,6 @@ static inline int next_audio_format(int format)
        for (i = 0; i < NUM_AUDIO_FORMATS; i = next_audio_format(i))
 
 /**
- * Call the init function of each supported audio format handler.
- */
-void afh_init(void)
-{
-       int i;
-
-       PARA_NOTICE_LOG("supported audio formats: %s\n", AUDIO_FORMAT_HANDLERS);
-       FOR_EACH_AUDIO_FORMAT(i) {
-               PARA_INFO_LOG("initializing %s handler\n",
-                       audio_format_name(i));
-               afl[i].init(&afl[i]);
-       }
-}
-
-/**
  * Tell whether an audio format handler provides chunk tables.
  *
  * Each audio format handler either provides a chunk table or supports dynamic
@@ -147,7 +88,7 @@ void afh_init(void)
  */
 bool afh_supports_dynamic_chunks(int audio_format_id)
 {
-       return afl[audio_format_id].get_chunk;
+       return afl[audio_format_id]->get_chunk;
 }
 
 /**
@@ -164,8 +105,8 @@ int guess_audio_format(const char *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];
+               for (j = 0; afl[i]->suffixes[j]; j++) {
+                       const char *p = afl[i]->suffixes[j];
                        int plen = strlen(p);
                        if (len < plen + 1)
                                continue;
@@ -187,7 +128,7 @@ static int get_file_info(int format, const char *path, char *data,
        const char *fmt = audio_format_name(format);
 
        memset(afhi, 0, sizeof(*afhi));
-       ret = afl[format].get_file_info(data, size, fd, afhi);
+       ret = afl[format]->get_file_info(data, size, fd, afhi);
        if (ret < 0) {
                PARA_WARNING_LOG("%s: %s format not detected: %s\n",
                        path, fmt, para_strerror(-ret));
@@ -308,7 +249,7 @@ __must_check int afh_get_chunk(long unsigned chunk_num, struct afh_info *afhi,
                uint8_t audio_format_id, const void *map, size_t mapsize,
                const char **buf, size_t *len, void **afh_context)
 {
-       struct audio_format_handler *afh = afl + audio_format_id;
+       struct audio_format_handler *afh = afl[audio_format_id];
 
        if (afh_supports_dynamic_chunks(audio_format_id)) {
                int ret;
@@ -345,7 +286,7 @@ __must_check int afh_get_chunk(long unsigned chunk_num, struct afh_info *afhi,
  */
 void afh_close(void *afh_context, uint8_t audio_format_id)
 {
-       struct audio_format_handler *afh = afl + audio_format_id;
+       struct audio_format_handler *afh = afl[audio_format_id];
 
        if (!afh_supports_dynamic_chunks(audio_format_id))
                return;
@@ -408,7 +349,7 @@ int32_t afh_get_start_chunk(int32_t approx_chunk_num,
 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;
+       struct audio_format_handler *afh = afl[audio_format_id];
 
        if (!map || !afhi || !afhi->header_len) {
                *buf = NULL;
@@ -431,7 +372,7 @@ void afh_get_header(struct afh_info *afhi, uint8_t audio_format_id,
  */
 void afh_free_header(char *header_buf, uint8_t audio_format_id)
 {
-       struct audio_format_handler *afh = afl + audio_format_id;
+       struct audio_format_handler *afh = afl[audio_format_id];
 
        if (afh->get_header)
                free(header_buf);
@@ -535,7 +476,7 @@ void set_max_chunk_size(struct afh_info *afhi)
 int afh_rewrite_tags(int audio_format_id, void *map, size_t mapsize,
                struct taginfo *tags, int output_fd, const char *filename)
 {
-       struct audio_format_handler *afh = afl + audio_format_id;
+       struct audio_format_handler *afh = afl[audio_format_id];
 
        if (!afh->rewrite_tags)
                return -ERRNO_TO_PARA_ERROR(ENOTSUP);
index 6525209..e5e87bd 100644 (file)
@@ -240,7 +240,6 @@ out:
 
 /** See \ref recv_init(). */
 const struct receiver lsg_recv_cmd_com_afh_user_data = {
-       .init = afh_init,
        .open = afh_recv_open,
        .close = afh_recv_close,
        .pre_select = afh_recv_pre_select,
index 45373ea..6e23683 100644 (file)
@@ -515,13 +515,12 @@ free_pfad:
 static const char * const flac_suffixes[] = {"flac", NULL};
 
 /**
- * The init function of the flac audio format handler.
+ * The audio format handler for flac (free lossless audio decoder).
  *
- * \param afh pointer to the struct to initialize
+ * It depends on libflac and on libogg.
  */
-void flac_afh_init(struct audio_format_handler *afh)
-{
-       afh->get_file_info = flac_get_file_info,
-       afh->suffixes = flac_suffixes;
-       afh->rewrite_tags = flac_rewrite_tags;
-}
+const struct audio_format_handler flac_afh = {
+       .get_file_info = flac_get_file_info,
+       .suffixes = flac_suffixes,
+       .rewrite_tags = flac_rewrite_tags,
+};
index 42dd753..e5027a0 100644 (file)
--- a/mp3_afh.c
+++ b/mp3_afh.c
@@ -682,15 +682,14 @@ static int mp3_get_file_info(char *map, size_t numbytes, int fd,
 static const char * const mp3_suffixes[] = {"mp3", NULL};
 
 /**
- * the init function of the mp3 audio format handler
+ * The mp3 audio format handler.
  *
- * \param afh pointer to the struct to initialize
+ * It does not depend on any libraries and is hence always compiled in.
  */
-void mp3_afh_init(struct audio_format_handler *afh)
-{
-       afh->get_file_info = mp3_get_file_info;
-       afh->suffixes = mp3_suffixes;
+const struct audio_format_handler mp3_afh = {
+       .get_file_info = mp3_get_file_info,
+       .suffixes = mp3_suffixes,
 #ifdef HAVE_LIBID3TAG
-       afh->rewrite_tags = mp3_rewrite_tags;
+       .rewrite_tags = mp3_rewrite_tags,
 #endif /* HAVE_LIBID3TAG */
-}
+};
index 93ad14b..5da339f 100644 (file)
--- a/ogg_afh.c
+++ b/ogg_afh.c
@@ -173,14 +173,15 @@ static int vorbis_rewrite_tags(const char *map, size_t mapsize,
 static const char * const ogg_suffixes[] = {"ogg", NULL};
 
 /**
- * The init function of the ogg vorbis audio format handler.
+ * The ogg vorbis audio format handler.
  *
- * \param afh Pointer to the struct to initialize.
+ * It should actually be called vorbis because the ogg container format is also
+ * employed for the speex and flac codecs. Both the ogg and the vorbis
+ * libraries must be installed to get this audio format handler.
  */
-void ogg_afh_init(struct audio_format_handler *afh)
-{
-       afh->get_file_info = ogg_vorbis_get_file_info;
-       afh->get_header = vorbis_get_header;
-       afh->suffixes = ogg_suffixes;
-       afh->rewrite_tags = vorbis_rewrite_tags;
-}
+const struct audio_format_handler ogg_afh = {
+       .get_file_info = ogg_vorbis_get_file_info,
+       .get_header = vorbis_get_header,
+       .suffixes = ogg_suffixes,
+       .rewrite_tags = vorbis_rewrite_tags
+};
index ed6fe5c..dca6cfb 100644 (file)
@@ -291,14 +291,15 @@ static void opus_get_header(void *map, size_t mapsize, char **buf,
 }
 
 /**
- * The init function of the ogg/opus audio format handler.
+ * The audio format handler for ogg/opus.
  *
- * \param afh Pointer to the struct to initialize.
+ * The opus codec was standardized by the Internet Engineering Task Force and
+ * is described in RFC 6716 (2012). The audio format handler depends on the ogg
+ * and the opus libraries.
  */
-void opus_afh_init(struct audio_format_handler *afh)
-{
-       afh->get_file_info = opus_get_file_info,
-       afh->get_header = opus_get_header;
-       afh->suffixes = opus_suffixes;
-       afh->rewrite_tags = opus_rewrite_tags;
-}
+const struct audio_format_handler opus_afh = {
+       .get_file_info = opus_get_file_info,
+       .get_header = opus_get_header,
+       .suffixes = opus_suffixes,
+       .rewrite_tags = opus_rewrite_tags,
+};
diff --git a/play.c b/play.c
index 647367a..c860208 100644 (file)
--- a/play.c
+++ b/play.c
@@ -1243,7 +1243,6 @@ int main(int argc, char *argv[])
 
        sched.default_timeout.tv_sec = 5;
        parse_config_or_die(argc, argv);
-       AFH_RECV->init();
        session_open();
        num_inputs = lls_num_inputs(play_lpr);
        init_shuffle_map();
index 6370cef..e0d50f4 100644 (file)
--- a/server.c
+++ b/server.c
@@ -583,9 +583,6 @@ static void server_init(int argc, char **argv, struct server_command_task *sct)
        init_ipc_or_die(); /* init mmd struct, mmd and log mutex */
        daemon_set_start_time();
        daemon_set_hooks(pre_log_hook, post_log_hook);
-       PARA_NOTICE_LOG("initializing audio format handlers\n");
-       afh_init();
-
        /*
         * Although afs uses its own signal handling we must ignore SIGUSR1
         * _before_ the afs child process gets born by init_afs() below.  It's
index e232364..caeacb1 100644 (file)
--- a/spx_afh.c
+++ b/spx_afh.c
@@ -248,13 +248,14 @@ static int spx_rewrite_tags(const char *map, size_t mapsize,
 static const char * const speex_suffixes[] = {"spx", "speex", NULL};
 
 /**
- * The init function of the ogg/speex audio format handler.
+ * The ogg/speex audio format handler.
  *
- * \param afh Pointer to the struct to initialize.
+ * This codec is considered obsolete because the opus codec surpasses its
+ * performance in all areas. It is only compiled in if both the ogg and the
+ * speex library are installed.
  */
-void spx_afh_init(struct audio_format_handler *afh)
-{
-       afh->get_file_info = spx_get_file_info,
-       afh->suffixes = speex_suffixes;
-       afh->rewrite_tags = spx_rewrite_tags;
-}
+const struct audio_format_handler spx_afh = {
+       .get_file_info = spx_get_file_info,
+       .suffixes = speex_suffixes,
+       .rewrite_tags = spx_rewrite_tags,
+};
index e6048a8..63e4967 100644 (file)
--- a/wma_afh.c
+++ b/wma_afh.c
@@ -646,13 +646,13 @@ out:
 static const char * const wma_suffixes[] = {"wma", NULL};
 
 /**
- * The init function of the wma audio format handler.
+ * The audio format handler for Windows Media Audio.
  *
- * \param afh Pointer to the struct to initialize.
+ * Only WMA version 2 is supported. This audio format handler does not depend
+ * on any third party libraries and is therefore always compiled in.
  */
-void wma_afh_init(struct audio_format_handler *afh)
-{
-       afh->get_file_info = wma_get_file_info;
-       afh->suffixes = wma_suffixes;
-       afh->rewrite_tags = wma_rewrite_tags;
-}
+const struct audio_format_handler wma_afh = {
+       .get_file_info = wma_get_file_info,
+       .suffixes = wma_suffixes,
+       .rewrite_tags = wma_rewrite_tags,
+};