1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // container-io.c - a unit test for parser/builder of supported containers.
4 //
5 // Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp>
6 //
7 // Licensed under the terms of the GNU General Public License, version 2.
8
9 #include <aconfig.h>
10 #ifdef HAVE_MEMFD_CREATE
11 #define _GNU_SOURCE
12 #endif
13
14 #include "../container.h"
15 #include "../misc.h"
16
17 #include "generator.h"
18
19 #ifdef HAVE_MEMFD_CREATE
20 #include <sys/mman.h>
21 #endif
22
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <stdbool.h>
26
27 #include <assert.h>
28
29 struct container_trial {
30 enum container_format format;
31
32 struct container_context cntr;
33 bool verbose;
34 };
35
test_builder(struct container_context * cntr,int fd,enum container_format format,snd_pcm_access_t access,snd_pcm_format_t sample_format,unsigned int samples_per_frame,unsigned int frames_per_second,void * frame_buffer,unsigned int frame_count,bool verbose)36 static void test_builder(struct container_context *cntr, int fd,
37 enum container_format format,
38 snd_pcm_access_t access,
39 snd_pcm_format_t sample_format,
40 unsigned int samples_per_frame,
41 unsigned int frames_per_second,
42 void *frame_buffer, unsigned int frame_count,
43 bool verbose)
44 {
45 snd_pcm_format_t sample;
46 unsigned int channels;
47 unsigned int rate;
48 uint64_t max_frame_count;
49 unsigned int handled_frame_count;
50 uint64_t total_frame_count;
51 int err;
52
53 err = container_builder_init(cntr, fd, format, verbose);
54 assert(err == 0);
55
56 sample = sample_format;
57 channels = samples_per_frame;
58 rate = frames_per_second;
59 max_frame_count = 0;
60 err = container_context_pre_process(cntr, &sample, &channels, &rate,
61 &max_frame_count);
62 assert(err == 0);
63 assert(sample == sample_format);
64 assert(channels == samples_per_frame);
65 assert(rate == frames_per_second);
66 assert(max_frame_count > 0);
67
68 handled_frame_count = frame_count;
69 err = container_context_process_frames(cntr, frame_buffer,
70 &handled_frame_count);
71 assert(err == 0);
72 assert(handled_frame_count > 0);
73 assert(handled_frame_count <= frame_count);
74
75 total_frame_count = 0;
76 err = container_context_post_process(cntr, &total_frame_count);
77 assert(err == 0);
78 assert(total_frame_count == frame_count);
79
80 container_context_destroy(cntr);
81 }
82
test_parser(struct container_context * cntr,int fd,enum container_format format,snd_pcm_access_t access,snd_pcm_format_t sample_format,unsigned int samples_per_frame,unsigned int frames_per_second,void * frame_buffer,unsigned int frame_count,bool verbose)83 static void test_parser(struct container_context *cntr, int fd,
84 enum container_format format,
85 snd_pcm_access_t access, snd_pcm_format_t sample_format,
86 unsigned int samples_per_frame,
87 unsigned int frames_per_second,
88 void *frame_buffer, unsigned int frame_count,
89 bool verbose)
90 {
91 snd_pcm_format_t sample;
92 unsigned int channels;
93 unsigned int rate;
94 uint64_t total_frame_count;
95 unsigned int handled_frame_count;
96 int err;
97
98 err = container_parser_init(cntr, fd, verbose);
99 assert(err == 0);
100
101 sample = sample_format;
102 channels = samples_per_frame;
103 rate = frames_per_second;
104 total_frame_count = 0;
105 err = container_context_pre_process(cntr, &sample, &channels, &rate,
106 &total_frame_count);
107 assert(err == 0);
108 assert(sample == sample_format);
109 assert(channels == samples_per_frame);
110 assert(rate == frames_per_second);
111 assert(total_frame_count == frame_count);
112
113 handled_frame_count = total_frame_count;
114 err = container_context_process_frames(cntr, frame_buffer,
115 &handled_frame_count);
116 assert(err == 0);
117 assert(handled_frame_count == frame_count);
118
119 total_frame_count = 0;
120 err = container_context_post_process(cntr, &total_frame_count);
121 assert(err == 0);
122 assert(total_frame_count == handled_frame_count);
123
124 container_context_destroy(cntr);
125 }
126
callback(struct test_generator * gen,snd_pcm_access_t access,snd_pcm_format_t sample_format,unsigned int samples_per_frame,void * frame_buffer,unsigned int frame_count)127 static int callback(struct test_generator *gen, snd_pcm_access_t access,
128 snd_pcm_format_t sample_format,
129 unsigned int samples_per_frame, void *frame_buffer,
130 unsigned int frame_count)
131 {
132 static const unsigned int entries[] = {
133 [0] = 44100,
134 [1] = 48000,
135 [2] = 88200,
136 [3] = 96000,
137 [4] = 176400,
138 [5] = 192000,
139 };
140 struct container_trial *trial = gen->private_data;
141 unsigned int frames_per_second;
142 const char *const name = "hoge";
143 unsigned int size;
144 void *buf;
145 int i;
146 int err = 0;
147
148 size = frame_count * samples_per_frame *
149 snd_pcm_format_physical_width(sample_format) / 8;
150 buf = malloc(size);
151 if (buf == NULL)
152 return -ENOMEM;
153
154 for (i = 0; i < ARRAY_SIZE(entries); ++i) {
155 int fd;
156 off64_t pos;
157
158 frames_per_second = entries[i];
159
160 #ifdef HAVE_MEMFD_CREATE
161 fd = memfd_create(name, 0);
162 #else
163 fd = open(name, O_RDWR | O_CREAT | O_TRUNC, 0644);
164 #endif
165 if (fd < 0) {
166 err = -errno;
167 break;
168 }
169
170 test_builder(&trial->cntr, fd, trial->format, access,
171 sample_format, samples_per_frame,
172 frames_per_second, frame_buffer, frame_count,
173 trial->verbose);
174
175 pos = lseek64(fd, 0, SEEK_SET);
176 if (pos < 0) {
177 err = -errno;
178 break;
179 }
180
181 test_parser(&trial->cntr, fd, trial->format, access,
182 sample_format, samples_per_frame, frames_per_second,
183 buf, frame_count, trial->verbose);
184
185 err = memcmp(buf, frame_buffer, size);
186 assert(err == 0);
187
188 close(fd);
189 }
190
191 free(buf);
192
193 return err;
194 }
195
main(int argc,const char * argv[])196 int main(int argc, const char *argv[])
197 {
198 static const uint64_t sample_format_masks[] = {
199 [CONTAINER_FORMAT_RIFF_WAVE] =
200 (1ull << SND_PCM_FORMAT_U8) |
201 (1ull << SND_PCM_FORMAT_S16_LE) |
202 (1ull << SND_PCM_FORMAT_S16_BE) |
203 (1ull << SND_PCM_FORMAT_S24_LE) |
204 (1ull << SND_PCM_FORMAT_S24_BE) |
205 (1ull << SND_PCM_FORMAT_S32_LE) |
206 (1ull << SND_PCM_FORMAT_S32_BE) |
207 (1ull << SND_PCM_FORMAT_FLOAT_LE) |
208 (1ull << SND_PCM_FORMAT_FLOAT_BE) |
209 (1ull << SND_PCM_FORMAT_FLOAT64_LE) |
210 (1ull << SND_PCM_FORMAT_FLOAT64_BE) |
211 (1ull << SND_PCM_FORMAT_MU_LAW) |
212 (1ull << SND_PCM_FORMAT_A_LAW) |
213 (1ull << SND_PCM_FORMAT_S24_3LE) |
214 (1ull << SND_PCM_FORMAT_S24_3BE) |
215 (1ull << SND_PCM_FORMAT_S20_3LE) |
216 (1ull << SND_PCM_FORMAT_S20_3BE) |
217 (1ull << SND_PCM_FORMAT_S18_3LE) |
218 (1ull << SND_PCM_FORMAT_S18_3BE),
219 [CONTAINER_FORMAT_AU] =
220 (1ull << SND_PCM_FORMAT_S8) |
221 (1ull << SND_PCM_FORMAT_S16_BE) |
222 (1ull << SND_PCM_FORMAT_S32_BE) |
223 (1ull << SND_PCM_FORMAT_FLOAT_BE) |
224 (1ull << SND_PCM_FORMAT_FLOAT64_BE) |
225 (1ull << SND_PCM_FORMAT_MU_LAW) |
226 (1ull << SND_PCM_FORMAT_A_LAW),
227 [CONTAINER_FORMAT_VOC] =
228 (1ull << SND_PCM_FORMAT_U8) |
229 (1ull << SND_PCM_FORMAT_S16_LE) |
230 (1ull << SND_PCM_FORMAT_MU_LAW) |
231 (1ull << SND_PCM_FORMAT_A_LAW),
232 [CONTAINER_FORMAT_RAW] =
233 (1ull << SND_PCM_FORMAT_S8) |
234 (1ull << SND_PCM_FORMAT_U8) |
235 (1ull << SND_PCM_FORMAT_S16_LE) |
236 (1ull << SND_PCM_FORMAT_S16_BE) |
237 (1ull << SND_PCM_FORMAT_U16_LE) |
238 (1ull << SND_PCM_FORMAT_U16_BE) |
239 (1ull << SND_PCM_FORMAT_S24_LE) |
240 (1ull << SND_PCM_FORMAT_S24_BE) |
241 (1ull << SND_PCM_FORMAT_U24_LE) |
242 (1ull << SND_PCM_FORMAT_U24_BE) |
243 (1ull << SND_PCM_FORMAT_S32_LE) |
244 (1ull << SND_PCM_FORMAT_S32_BE) |
245 (1ull << SND_PCM_FORMAT_U32_LE) |
246 (1ull << SND_PCM_FORMAT_U32_BE) |
247 (1ull << SND_PCM_FORMAT_FLOAT_LE) |
248 (1ull << SND_PCM_FORMAT_FLOAT_BE) |
249 (1ull << SND_PCM_FORMAT_FLOAT64_LE) |
250 (1ull << SND_PCM_FORMAT_FLOAT64_BE) |
251 (1ull << SND_PCM_FORMAT_IEC958_SUBFRAME_LE) |
252 (1ull << SND_PCM_FORMAT_IEC958_SUBFRAME_BE) |
253 (1ull << SND_PCM_FORMAT_MU_LAW) |
254 (1ull << SND_PCM_FORMAT_A_LAW) |
255 (1ull << SND_PCM_FORMAT_S24_3LE) |
256 (1ull << SND_PCM_FORMAT_S24_3BE) |
257 (1ull << SND_PCM_FORMAT_U24_3LE) |
258 (1ull << SND_PCM_FORMAT_U24_3BE) |
259 (1ull << SND_PCM_FORMAT_S20_3LE) |
260 (1ull << SND_PCM_FORMAT_S20_3BE) |
261 (1ull << SND_PCM_FORMAT_U20_3LE) |
262 (1ull << SND_PCM_FORMAT_U20_3BE) |
263 (1ull << SND_PCM_FORMAT_S18_3LE) |
264 (1ull << SND_PCM_FORMAT_S18_3BE) |
265 (1ull << SND_PCM_FORMAT_U18_3LE) |
266 (1ull << SND_PCM_FORMAT_U18_3BE) |
267 (1ull << SND_PCM_FORMAT_DSD_U8) |
268 (1ull << SND_PCM_FORMAT_DSD_U16_LE) |
269 (1ull << SND_PCM_FORMAT_DSD_U32_LE) |
270 (1ull << SND_PCM_FORMAT_DSD_U16_BE) |
271 (1ull << SND_PCM_FORMAT_DSD_U32_BE),
272 };
273 static const uint64_t access_mask =
274 (1ull << SND_PCM_ACCESS_MMAP_INTERLEAVED) |
275 (1ull << SND_PCM_ACCESS_RW_INTERLEAVED);
276 struct test_generator gen = {0};
277 struct container_trial *trial;
278 int i;
279 int begin;
280 int end;
281 bool verbose;
282 int err;
283
284 if (argc > 1) {
285 char *term;
286 begin = strtol(argv[1], &term, 10);
287 if (errno || *term != '\0')
288 return EXIT_FAILURE;
289 if (begin < CONTAINER_FORMAT_RIFF_WAVE &&
290 begin > CONTAINER_FORMAT_RAW)
291 return -EXIT_FAILURE;
292 end = begin + 1;
293 verbose = true;
294 } else {
295 begin = CONTAINER_FORMAT_RIFF_WAVE;
296 end = CONTAINER_FORMAT_RAW + 1;
297 verbose = false;
298 }
299
300 for (i = begin; i < end; ++i) {
301 err = generator_context_init(&gen, access_mask,
302 sample_format_masks[i],
303 1, 32, 23, 3000, 512,
304 sizeof(struct container_trial));
305 if (err >= 0) {
306 trial = gen.private_data;
307 trial->format = i;
308 trial->verbose = verbose;
309 err = generator_context_run(&gen, callback);
310 }
311
312 generator_context_destroy(&gen);
313
314 if (err < 0)
315 break;
316 }
317
318 if (err < 0) {
319 printf("%s\n", strerror(-err));
320 return EXIT_FAILURE;
321 }
322
323 return EXIT_SUCCESS;
324 }
325