• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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