• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // mapper-io.c - a unit test for muxer/demuxer for PCM frames on buffer.
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 "../mapper.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 mapper_trial {
30 	enum container_format cntr_format;
31 	struct container_context *cntrs;
32 
33 	char **paths;
34 
35 	struct mapper_context mapper;
36 	bool verbose;
37 };
38 
test_demuxer(struct mapper_context * mapper,snd_pcm_access_t access,unsigned int bytes_per_sample,unsigned int samples_per_frame,unsigned int frames_per_buffer,void * frame_buffer,unsigned int frame_count,struct container_context * cntrs,unsigned int cntr_count,bool verbose)39 static void test_demuxer(struct mapper_context *mapper, snd_pcm_access_t access,
40 			 unsigned int bytes_per_sample,
41 			 unsigned int samples_per_frame,
42 			 unsigned int frames_per_buffer,
43 			 void *frame_buffer, unsigned int frame_count,
44 			 struct container_context *cntrs,
45 			 unsigned int cntr_count, bool verbose)
46 {
47 	unsigned int total_frame_count;
48 	int err;
49 
50 	err = mapper_context_init(mapper, MAPPER_TYPE_DEMUXER, cntr_count,
51 				  verbose);
52 	assert(err == 0);
53 
54 	err = mapper_context_pre_process(mapper, access, bytes_per_sample,
55 					 samples_per_frame, frames_per_buffer,
56 					 cntrs);
57 	assert(err == 0);
58 
59 	total_frame_count = frame_count;
60 	err = mapper_context_process_frames(mapper, frame_buffer,
61 					    &total_frame_count, cntrs);
62 	assert(err == 0);
63 	assert(total_frame_count == frame_count);
64 
65 	mapper_context_post_process(mapper);
66 	mapper_context_destroy(mapper);
67 }
68 
test_demux(struct mapper_trial * trial,snd_pcm_access_t access,snd_pcm_format_t sample_format,unsigned int samples_per_frame,unsigned int frames_per_second,unsigned int frames_per_buffer,void * frame_buffer,unsigned int frame_count,int * cntr_fds,unsigned int cntr_count)69 static int test_demux(struct mapper_trial *trial, snd_pcm_access_t access,
70 		      snd_pcm_format_t sample_format,
71 		      unsigned int samples_per_frame,
72 		      unsigned int frames_per_second,
73 		      unsigned int frames_per_buffer,
74 		      void *frame_buffer, unsigned int frame_count,
75 		      int *cntr_fds, unsigned int cntr_count)
76 {
77 	struct container_context *cntrs = trial->cntrs;
78 	enum container_format cntr_format = trial->cntr_format;
79 	unsigned int bytes_per_sample;
80 	uint64_t total_frame_count;
81 	int i;
82 	int err = 0;
83 
84 	for (i = 0; i < cntr_count; ++i) {
85 		snd_pcm_format_t format;
86 		unsigned int channels;
87 		unsigned int rate;
88 
89 		err = container_builder_init(cntrs + i, cntr_fds[i], cntr_format, 0);
90 		if (err < 0)
91 			goto end;
92 
93 		format = sample_format;
94 		rate = frames_per_second;
95 		total_frame_count = frame_count;
96 		if (cntr_count > 1)
97 			channels = 1;
98 		else
99 			channels = samples_per_frame;
100 		err = container_context_pre_process(cntrs + i, &format,
101 						    &channels, &rate,
102 						    &total_frame_count);
103 		if (err < 0)
104 			goto end;
105 		assert(format == sample_format);
106 		assert(rate == frames_per_second);
107 		assert(total_frame_count >= 0);
108 		if (cntr_count > 1)
109 			assert(channels == 1);
110 		else
111 			assert(channels == samples_per_frame);
112 	}
113 
114 	bytes_per_sample = snd_pcm_format_physical_width(sample_format) / 8;
115 	test_demuxer(&trial->mapper, access, bytes_per_sample,
116 		     samples_per_frame, frames_per_buffer, frame_buffer,
117 		     frame_count, cntrs, cntr_count, trial->verbose);
118 
119 	for (i = 0; i < cntr_count; ++i) {
120 		container_context_post_process(cntrs + i, &total_frame_count);
121 		assert(total_frame_count == frame_count);
122 	}
123 end:
124 	for (i = 0; i < cntr_count; ++i)
125 		container_context_destroy(cntrs + i);
126 
127 	return err;
128 }
129 
test_muxer(struct mapper_context * mapper,snd_pcm_access_t access,unsigned int bytes_per_sample,unsigned int samples_per_frame,unsigned int frames_per_buffer,void * frame_buffer,unsigned int frame_count,struct container_context * cntrs,unsigned int cntr_count,bool verbose)130 static void test_muxer(struct mapper_context *mapper, snd_pcm_access_t access,
131 		       unsigned int bytes_per_sample,
132 		       unsigned int samples_per_frame,
133 		       unsigned int frames_per_buffer,
134 		       void *frame_buffer, unsigned int frame_count,
135 		       struct container_context *cntrs,
136 		       unsigned int cntr_count, bool verbose)
137 {
138 	unsigned int total_frame_count;
139 	int err;
140 
141 	err = mapper_context_init(mapper, MAPPER_TYPE_MUXER, cntr_count,
142 				  verbose);
143 	assert(err == 0);
144 
145 	err = mapper_context_pre_process(mapper, access, bytes_per_sample,
146 					 samples_per_frame, frames_per_buffer,
147 					 cntrs);
148 	assert(err == 0);
149 
150 	total_frame_count = frame_count;
151 	err = mapper_context_process_frames(mapper, frame_buffer,
152 					    &total_frame_count, cntrs);
153 	assert(err == 0);
154 	assert(total_frame_count == frame_count);
155 
156 	mapper_context_post_process(mapper);
157 	mapper_context_destroy(mapper);
158 }
159 
test_mux(struct mapper_trial * trial,snd_pcm_access_t access,snd_pcm_format_t sample_format,unsigned int samples_per_frame,unsigned int frames_per_second,unsigned int frames_per_buffer,void * frame_buffer,unsigned int frame_count,int * cntr_fds,unsigned int cntr_count)160 static int test_mux(struct mapper_trial *trial, snd_pcm_access_t access,
161 		    snd_pcm_format_t sample_format,
162 		    unsigned int samples_per_frame,
163 		    unsigned int frames_per_second,
164 		    unsigned int frames_per_buffer,
165 		    void *frame_buffer, unsigned int frame_count,
166 		    int *cntr_fds, unsigned int cntr_count)
167 {
168 	struct container_context *cntrs = trial->cntrs;
169 	unsigned int bytes_per_sample;
170 	uint64_t total_frame_count;
171 	int i;
172 	int err = 0;
173 
174 	for (i = 0; i < cntr_count; ++i) {
175 		snd_pcm_format_t format;
176 		unsigned int channels;
177 		unsigned int rate;
178 
179 		err = container_parser_init(cntrs + i, cntr_fds[i], 0);
180 		if (err < 0)
181 			goto end;
182 
183 		format = sample_format;
184 		rate = frames_per_second;
185 		if (cntr_count > 1)
186 			channels = 1;
187 		else
188 			channels = samples_per_frame;
189 		err = container_context_pre_process(cntrs + i, &format,
190 						    &channels, &rate,
191 						    &total_frame_count);
192 		if (err < 0)
193 			goto end;
194 
195 		assert(format == sample_format);
196 		assert(rate == frames_per_second);
197 		assert(total_frame_count == frame_count);
198 		if (cntr_count > 1)
199 			assert(channels == 1);
200 		else
201 			assert(channels == samples_per_frame);
202 	}
203 
204 	bytes_per_sample = snd_pcm_format_physical_width(sample_format) / 8;
205 	test_muxer(&trial->mapper, access, bytes_per_sample, samples_per_frame,
206 		   frames_per_buffer, frame_buffer, frame_count, cntrs,
207 		   cntr_count, trial->verbose);
208 
209 	for (i = 0; i < cntr_count; ++i) {
210 		container_context_post_process(cntrs + i, &total_frame_count);
211 		assert(total_frame_count == frame_count);
212 	}
213 end:
214 	for (i = 0; i < cntr_count; ++i)
215 		container_context_destroy(cntrs + i);
216 
217 	return err;
218 }
219 
test_mapper(struct mapper_trial * trial,snd_pcm_access_t access,snd_pcm_format_t sample_format,unsigned int samples_per_frame,unsigned int frames_per_second,void * frame_buffer,void * check_buffer,unsigned int frame_count,unsigned int cntr_count)220 static int test_mapper(struct mapper_trial *trial, snd_pcm_access_t access,
221 		    snd_pcm_format_t sample_format,
222 		    unsigned int samples_per_frame,
223 		    unsigned int frames_per_second, void *frame_buffer,
224 		    void *check_buffer, unsigned int frame_count,
225 		    unsigned int cntr_count)
226 {
227 	int *cntr_fds;
228 	unsigned int frames_per_buffer;
229 	int i;
230 	int err;
231 
232 	// Use a buffer aligned by typical size of page frame.
233 	frames_per_buffer = ((frame_count + 4096) / 4096) * 4096;
234 
235 	cntr_fds = calloc(cntr_count, sizeof(*cntr_fds));
236 	if (cntr_fds == NULL)
237 		return -ENOMEM;
238 
239 	for (i = 0; i < cntr_count; ++i) {
240 		const char *path = trial->paths[i];
241 
242 #ifdef HAVE_MEMFD_CREATE
243 		cntr_fds[i] = memfd_create(path, 0);
244 #else
245 		cntr_fds[i] = open(path, O_RDWR | O_CREAT | O_TRUNC, 0644);
246 #endif
247 		if (cntr_fds[i] < 0) {
248 			err = -errno;
249 			goto end;
250 		}
251 	}
252 
253 	err = test_demux(trial, access, sample_format, samples_per_frame,
254 			 frames_per_second, frames_per_buffer, frame_buffer,
255 			 frame_count, cntr_fds, cntr_count);
256 	if (err < 0)
257 		goto end;
258 
259 	for (i = 0; i < cntr_count; ++i) {
260 		off64_t pos = lseek64(cntr_fds[i], 0, SEEK_SET);
261 		if (pos != 0) {
262 			err = -EIO;
263 			goto end;
264 		}
265 	}
266 
267 	err = test_mux(trial, access, sample_format, samples_per_frame,
268 		       frames_per_second, frames_per_buffer, check_buffer,
269 		       frame_count, cntr_fds, cntr_count);
270 end:
271 	for (i = 0; i < cntr_count; ++i)
272 		close(cntr_fds[i]);
273 
274 	free(cntr_fds);
275 
276 	return err;
277 }
278 
test_i_buf(struct mapper_trial * trial,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,unsigned int cntr_count)279 static int test_i_buf(struct mapper_trial *trial, snd_pcm_access_t access,
280 		      snd_pcm_format_t sample_format,
281 		      unsigned int samples_per_frame,
282 		      unsigned int frames_per_second, void *frame_buffer,
283 		      unsigned int frame_count, unsigned int cntr_count)
284 {
285 	unsigned int size;
286 	char *buf;
287 	int err;
288 
289 	size = frame_count * samples_per_frame *
290 			snd_pcm_format_physical_width(sample_format) / 8;
291 	buf = malloc(size);
292 	if (buf == 0)
293 		return -ENOMEM;
294 	memset(buf, 0, size);
295 
296 	// Test multiple target.
297 	err = test_mapper(trial, access, sample_format, samples_per_frame,
298 			  frames_per_second, frame_buffer, buf,
299 			  frame_count, cntr_count);
300 	if (err < 0)
301 		goto end;
302 	err = memcmp(frame_buffer, buf, size);
303 	assert(err == 0);
304 
305 	// Test single target.
306 	err = test_mapper(trial, access, sample_format, samples_per_frame,
307 			  frames_per_second, frame_buffer, buf,
308 			  frame_count, 1);
309 	if (err < 0)
310 		goto end;
311 	err = memcmp(frame_buffer, buf, size);
312 	assert(err == 0);
313 end:
314 	free(buf);
315 
316 	return err;
317 }
318 
test_vector(struct mapper_trial * trial,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,unsigned int cntr_count)319 static int test_vector(struct mapper_trial *trial, snd_pcm_access_t access,
320 		       snd_pcm_format_t sample_format,
321 		       unsigned int samples_per_frame,
322 		       unsigned int frames_per_second, void *frame_buffer,
323 		       unsigned int frame_count, unsigned int cntr_count)
324 {
325 	unsigned int size;
326 	char **bufs;
327 	int i;
328 	int err;
329 
330 	bufs = calloc(cntr_count, sizeof(*bufs));
331 	if (bufs == NULL)
332 		return -ENOMEM;
333 
334 	size = frame_count * snd_pcm_format_physical_width(sample_format) / 8;
335 
336 	for (i = 0; i < cntr_count; ++i) {
337 		bufs[i] = malloc(size);
338 		if (bufs[i] == NULL) {
339 			err = -ENOMEM;
340 			goto end;
341 		}
342 		memset(bufs[i], 0, size);
343 	}
344 
345 	// Test multiple target.
346 	err = test_mapper(trial, access, sample_format, samples_per_frame,
347 			  frames_per_second, frame_buffer, bufs,
348 			  frame_count, cntr_count);
349 	if (err < 0)
350 		goto end;
351 	for (i = 0; i < cntr_count; ++i) {
352 		char **target = frame_buffer;
353 		err = memcmp(target[i], bufs[i], size);
354 		assert(err == 0);
355 	}
356 
357 	// Test single target.
358 	err = test_mapper(trial, access, sample_format, samples_per_frame,
359 			  frames_per_second, frame_buffer, bufs,
360 			  frame_count, 1);
361 	if (err < 0)
362 		goto end;
363 	for (i = 0; i < cntr_count; ++i) {
364 		char **target = frame_buffer;
365 		err = memcmp(target[i], bufs[i], size);
366 		assert(err == 0);
367 	}
368 end:
369 	for (i = 0; i < cntr_count; ++i) {
370 		if (bufs[i])
371 			free(bufs[i]);
372 	}
373 	free(bufs);
374 
375 	return err;
376 }
377 
test_n_buf(struct mapper_trial * trial,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,unsigned int cntr_count)378 static int test_n_buf(struct mapper_trial *trial, snd_pcm_access_t access,
379 		      snd_pcm_format_t sample_format,
380 		      unsigned int samples_per_frame,
381 		      unsigned int frames_per_second, void *frame_buffer,
382 		      unsigned int frame_count, unsigned int cntr_count)
383 {
384 	char *test_buf = frame_buffer;
385 	unsigned int size;
386 	char **test_vec;
387 	int i;
388 	int err;
389 
390 	size = frame_count * snd_pcm_format_physical_width(sample_format) / 8;
391 
392 	test_vec = calloc(cntr_count * 2, sizeof(*test_vec));
393 	if (test_vec == NULL)
394 		return -ENOMEM;
395 
396 	for (i = 0; i < cntr_count; ++i)
397 		test_vec[i] = test_buf + size * i;
398 
399 	err = test_vector(trial, access, sample_format, samples_per_frame,
400 			  frames_per_second, test_vec, frame_count, cntr_count);
401 	free(test_vec);
402 
403 	return err;
404 }
405 
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)406 static int callback(struct test_generator *gen, snd_pcm_access_t access,
407 		    snd_pcm_format_t sample_format,
408 		    unsigned int samples_per_frame, void *frame_buffer,
409 		    unsigned int frame_count)
410 {
411 
412 	int (*handler)(struct mapper_trial *trial, snd_pcm_access_t access,
413 		       snd_pcm_format_t sample_format,
414 		       unsigned int samples_per_frame,
415 		       unsigned int frames_per_second, void *frame_buffer,
416 		       unsigned int frame_count, unsigned int cntr_count);
417 	struct mapper_trial *trial = gen->private_data;
418 
419 	if (access == SND_PCM_ACCESS_RW_NONINTERLEAVED)
420 		handler = test_vector;
421 	else if (access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED)
422 		handler = test_n_buf;
423 	else
424 		handler = test_i_buf;
425 
426 	return handler(trial, access, sample_format, samples_per_frame, 48000,
427 		       frame_buffer, frame_count, samples_per_frame);
428 };
429 
main(int argc,const char * argv[])430 int main(int argc, const char *argv[])
431 {
432 	// Test 8/16/18/20/24/32/64 bytes per sample.
433 	static const uint64_t sample_format_mask =
434 			(1ull << SND_PCM_FORMAT_U8) |
435 			(1ull << SND_PCM_FORMAT_S16_LE) |
436 			(1ull << SND_PCM_FORMAT_S18_3LE) |
437 			(1ull << SND_PCM_FORMAT_S20_3LE) |
438 			(1ull << SND_PCM_FORMAT_S24_LE) |
439 			(1ull << SND_PCM_FORMAT_S32_LE) |
440 			(1ull << SND_PCM_FORMAT_FLOAT64_LE);
441 	uint64_t access_mask;
442 	struct test_generator gen = {0};
443 	struct mapper_trial *trial;
444 	struct container_context *cntrs;
445 	unsigned int samples_per_frame;
446 	char **paths = NULL;
447 	snd_pcm_access_t access;
448 	bool verbose;
449 	int i;
450 	int err;
451 
452 	// Test up to 32 channels.
453 	samples_per_frame = 32;
454 	cntrs = calloc(samples_per_frame, sizeof(*cntrs));
455 	if (cntrs == NULL)
456 		return -ENOMEM;
457 
458 	paths = calloc(samples_per_frame, sizeof(*paths));
459 	if (paths == NULL) {
460 		err = -ENOMEM;
461 		goto end;
462 	}
463 	for (i = 0; i < samples_per_frame; ++i) {
464 		paths[i] = malloc(8);
465 		if (paths[i] == NULL) {
466 			err = -ENOMEM;
467 			goto end;
468 		}
469 		snprintf(paths[i], 8, "hoge%d", i);
470 	}
471 
472 	if (argc > 1) {
473 		char *term;
474 		access = strtol(argv[1], &term, 10);
475 		if (errno != 0 || *term != '\0') {
476 			err = -EINVAL;;
477 			goto end;
478 		}
479 		if (access < SND_PCM_ACCESS_MMAP_INTERLEAVED &&
480 		    access > SND_PCM_ACCESS_RW_NONINTERLEAVED) {
481 			err = -EINVAL;
482 			goto end;
483 		}
484 		if (access == SND_PCM_ACCESS_MMAP_COMPLEX) {
485 			err = -EINVAL;
486 			goto end;
487 		}
488 
489 		access_mask = 1ull << access;
490 		verbose = true;
491 	} else {
492 		access_mask = (1ull << SND_PCM_ACCESS_MMAP_INTERLEAVED) |
493 			      (1ull << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) |
494 			      (1ull << SND_PCM_ACCESS_RW_INTERLEAVED) |
495 			      (1ull << SND_PCM_ACCESS_RW_NONINTERLEAVED);
496 		verbose = false;
497 	}
498 
499 	err = generator_context_init(&gen, access_mask, sample_format_mask,
500 				     1, samples_per_frame,
501 				     23, 4500, 1024,
502 				     sizeof(struct mapper_trial));
503 	if (err < 0)
504 		goto end;
505 
506 	trial = gen.private_data;
507 	trial->cntrs = cntrs;
508 	trial->cntr_format = CONTAINER_FORMAT_RIFF_WAVE;
509 	trial->paths = paths;
510 	trial->verbose = verbose;
511 	err = generator_context_run(&gen, callback);
512 
513 	generator_context_destroy(&gen);
514 end:
515 	if (paths) {
516 		for (i = 0; i < samples_per_frame; ++i)
517 			free(paths[i]);
518 		free(paths);
519 	}
520 	free(cntrs);
521 
522 	if (err < 0) {
523 		printf("%s\n", strerror(-err));
524 		return EXIT_FAILURE;
525 	}
526 
527 	return EXIT_SUCCESS;
528 }
529