1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
/* 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);
|