/* SPDX-License-Identifier: GPL-2.0 */ /** \file afh.h Audio format handlers * * The mission of an audio format handler is to tell whether a given file * is an audio file of a certain type and to retrieve information about the * file. The various audio format handlers are linked into para_server(1), * para_afh(1) and para_recv(1). Each audio format handler is implemented * in its own file. For example, \ref mp3_afh.c contains the implementation * of the mp3 audio format handler. All functions declared here are defined * in \ref afh_common.c. * * Audio format handlers need to define only one non-static symbol: * an instance of struct \ref audio_format_handler. Its methods are * called from the audio file selector and the virtual streaming system, * among others. For example, each time an audio file is added, the \ref * audio_format_handler::get_file_info() method is called to initialize an * \ref afh_info structure with metadata stored in the tags (artist, title, * etc.) and with information needed for streaming. A serialized version * of this structure is stored in the audio file table, and loaded again * when the file is opened for streaming. */ /** * The tags used by all audio format handlers. * * Paraslash only cares about the five metadata tags described in this * structure. Each audio format handler is capable of reading and modifying * these tags. */ struct taginfo { /** TPE1 (id3v2) / ARTIST (vorbis) / ART (aac)/ author(spx) */ char *artist; /** TIT2/TITLE/nam */ char *title; /** TDRC/YEAR/day */ char *year; /** TALB/ALBUM/alb */ char *album; /** COMM/COMMENT/cmt */ char *comment; }; /** * Metadata extracted from an audio file. * * The \ref audio_format_handler::compute_afhi() method of each audio format * handler initializes an instance of this format independent structure * with information extracted from the given audio file. The various * pointers are initialized by allocating help memory at runtime because * the extracted information is of variable size. See \ref clear_afhi() * for how to deallocate an instance. * * Since a serialized version of this structure is stored in the database * of the audio file selector, we use fixed size integer types such as * uint32_t here. */ struct afh_info { /** The number of chunks this audio file contains. */ uint32_t chunks_total; /** The length of the audio file in seconds. */ uint32_t seconds_total; /** Additional audio format specific information. */ char *techinfo; /** Id3 tags, vorbis comments, aac tags, etc. */ struct taginfo tags; /** * The table that specifies the offset of the individual pieces in * the current audio file. */ uint32_t *chunk_table; /** Size of the largest chunk, introduced in v0.6.0. */ uint32_t max_chunk_size; /** Period of time between sending data chunks. */ struct timeval chunk_tv; /** Size of the header chunk (if any) in bytes. * * If a client connects in the middle of the stream, the receiving * decoder might need to know some information about the audio file * in order to initialize itself. This can be achieved by asking * the virtual streaming system to send an additional "header" chunk * before the first data chunk. A value of zero means that the virtual * streaming system should not send any header chunks. */ uint32_t header_len; /** The number of channels. */ uint8_t channels; /** Sampling rate in Hertz. */ uint16_t frequency; /** Exact meaning depends on audio format. */ uint16_t bitrate; }; /** * This is what the audio file selector passes to the virtual streaming * system at stream start. */ struct audio_file_data { /** Vss needs this for streaming. */ struct afh_info afhi; /** Needed to get the audio file header. */ uint8_t audio_format_id; }; /** * Definition of an audio format handler. * * Each audio format defines a constant instance of this structure, and this * is usually the only non-static symbol of the corresponding _afh.c file. */ struct audio_format_handler { /** Typical file endings, often only one. */ const char * const *suffixes; /** * Check if this audio format handler can handle the file. * * A negative return value indicates that this audio format handler * is unable to handle the file. On success, the function must fill * in the given afh_info structure. */ int (*get_file_info)(char *map, size_t numbytes, struct afh_info *afhi); /** Optional, used for header-rewriting. See \ref afh_get_header(). */ void (*get_header)(void *map, size_t mapsize, char **buf, size_t *len); /** * An audio format handler may signify support for dynamic chunks by * defining ->get_chunk below. In this case the vss calls ->open() at * BOS, ->get_chunk() for each chunk while streaming, and ->close() at * EOS. The chunk table is not accessed at all. * * The function may return its (opaque) context through the last * argument. The returned pointer is passed to subsequent calls to * ->get_chunk() and ->close(). */ int (*open)(const void *map, size_t mapsize, void **afh_context); /** * Return a reference to one chunk. The returned pointer points to a * portion of the memory mapped audio file. The caller must not call * free() on it. */ int (*get_chunk)(uint32_t chunk_num, void *afh_context, const char **buf, uint32_t *len); /** Deallocate the resources occupied by ->open(). */ void (*close)(void *afh_context); /** * Write audio file with altered tags. * * This function shall create a copy of the memory-mapped file, but * with altered metadata tags according to the tags argument. The * output file descriptor has been opened by the caller and must not * be closed in this function. */ int (*rewrite_tags)(const char *map, size_t mapsize, struct taginfo *tags, int output_fd); }; int guess_audio_format(const char *name); int compute_afhi(const char *path, char *data, size_t size, struct afh_info *afhi); const char *audio_format_name(int); __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, uint32_t *len, void **afh_context); void afh_close(void *afh_context, uint8_t audio_format_id); int32_t afh_get_start_chunk(int32_t approx_chunk_num, const struct afh_info *afhi, uint8_t audio_format_id); 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); void clear_afhi(struct afh_info *afhi); unsigned afh_get_afhi_txt(int audio_format_num, struct afh_info *afhi, char **result); int afh_rewrite_tags(int audio_format_id, void *map, size_t mapsize, struct taginfo *tags, int output_fd); void set_max_chunk_size(struct afh_info *afhi); bool afh_supports_dynamic_chunks(int audio_format_id);