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 29struct container_trial { 30 enum container_format format; 31 32 struct container_context cntr; 33 bool verbose; 34}; 35 36static 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 83static 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 127static 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 off_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 = lseek(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 196int 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