const char *status_item_list[] = {STATUS_ITEMS};
/**
- * The list of supported audio formats.
- *
- * We always define the full array of audio formats even if some audio formats
- * were not compiled in. This is because for each audio file the number of its
- * audio format is stored in the database. We don't want these numbers to become
- * stale just because the user installed a new version of paraslash that
- * supports a different set of audio formats.
- *
- * It can still be easily detected whether an audio format is compiled in by
- * checking if the init function pointer is not \p NULL.
+ * For each audio file the number of its audio format is stored in the
+ * database. Therefore this list, in particular its order, is part of the ABI.
+ * So it's only OK to append new audio formats. All audio formats are listed
+ * here, regardless of whether the audio format handler is compiled in.
+ */
+#define ALL_AUDIO_FORMATS \
+ AUDIO_FORMAT(mp3) \
+ AUDIO_FORMAT(ogg) \
+ AUDIO_FORMAT(aac) \
+ AUDIO_FORMAT(wma) \
+ AUDIO_FORMAT(spx) \
+ AUDIO_FORMAT(flac) \
+ AUDIO_FORMAT(opus) \
+
+#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[] = {
{
- .name = "mp3",
.init = mp3_afh_init,
},
{
- .name = "ogg",
#if defined(HAVE_OGG) && defined(HAVE_VORBIS)
.init = ogg_afh_init,
#endif
},
{
- .name = "aac",
#if defined(HAVE_FAAD)
.init = aac_afh_init,
#endif
},
{
- .name = "wma",
.init = wma_afh_init,
},
{
- .name = "spx",
#if defined(HAVE_OGG) && defined(HAVE_SPEEX)
.init = spx_afh_init,
#endif
},
{
- .name = "flac",
#if defined(HAVE_OGG) && defined(HAVE_FLAC)
.init = flac_afh_init,
#endif
},
{
- .name = "opus",
#if defined(HAVE_OGG) && defined(HAVE_OPUS)
.init = opus_afh_init,
#endif
},
- {
- .name = NULL,
- }
};
+/** This includes audio formats not compiled in. */
+#define NUM_AUDIO_FORMATS (ARRAY_SIZE(afl))
+
+/**
+ * Get the name of the given audio format.
+ *
+ * \param i The audio format number.
+ *
+ * \return This returns a pointer to statically allocated memory so it
+ * must not be freed by the caller.
+ */
+const char *audio_format_name(int i)
+{
+ if (i < 0 || i >= NUM_AUDIO_FORMATS)
+ return "???";
+ return audio_format_names[i];
+}
+
static inline int next_audio_format(int format)
{
for (;;) {
- if (!afl[format].name)
- return format;
format++;
+ if (format >= NUM_AUDIO_FORMATS)
+ return format;
if (afl[format].init)
return format;
}
}
/** Iterate over each supported audio format. */
-#define FOR_EACH_AUDIO_FORMAT(i) for (i = 0; afl[i].name; i = next_audio_format(i))
+#define FOR_EACH_AUDIO_FORMAT(i) \
+ for (i = 0; i < NUM_AUDIO_FORMATS; i = next_audio_format(i))
/**
* Call the init function of each supported audio format handler.
return -E_AUDIO_FORMAT;
}
-/**
- * Get the name of the given audio format.
- *
- * \param i The audio format number.
- *
- * \return This returns a pointer to statically allocated memory so it
- * must not be freed by the caller.
- */
-const char *audio_format_name(int i)
-{
- if (i < 0 || i >= ARRAY_SIZE(afl) - 1)
- return "???";
- return afl[i].name;
-}
-
static int get_file_info(int format, const char *path, char *data,
size_t size, int fd, struct afh_info *afhi)
{
if (ret < 0)
return ret;
}
- ret = afl[audio_format_id].get_chunk(chunk_num, *afh_context,
+ ret = afh->get_chunk(chunk_num, *afh_context,
buf, len);
if (ret < 0) {
afh->close(*afh_context);