1c72fcc34Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 2c72fcc34Sopenharmony_ci// 3c72fcc34Sopenharmony_ci// allocator.h - a header of a generator for test with buffers of PCM frames. 4c72fcc34Sopenharmony_ci// 5c72fcc34Sopenharmony_ci// Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp> 6c72fcc34Sopenharmony_ci// 7c72fcc34Sopenharmony_ci// Licensed under the terms of the GNU General Public License, version 2. 8c72fcc34Sopenharmony_ci 9c72fcc34Sopenharmony_ci#include "generator.h" 10c72fcc34Sopenharmony_ci 11c72fcc34Sopenharmony_ci#include <stdlib.h> 12c72fcc34Sopenharmony_ci 13c72fcc34Sopenharmony_ci#include <sys/types.h> 14c72fcc34Sopenharmony_ci#include <sys/stat.h> 15c72fcc34Sopenharmony_ci#include <fcntl.h> 16c72fcc34Sopenharmony_ci 17c72fcc34Sopenharmony_ci#include <unistd.h> 18c72fcc34Sopenharmony_ci 19c72fcc34Sopenharmony_ciint generator_context_init(struct test_generator *gen, 20c72fcc34Sopenharmony_ci uint64_t access_mask, uint64_t sample_format_mask, 21c72fcc34Sopenharmony_ci unsigned int min_samples_per_frame, 22c72fcc34Sopenharmony_ci unsigned int max_samples_per_frame, 23c72fcc34Sopenharmony_ci unsigned int min_frame_count, 24c72fcc34Sopenharmony_ci unsigned int max_frame_count, 25c72fcc34Sopenharmony_ci unsigned int step_frame_count, 26c72fcc34Sopenharmony_ci unsigned int private_size) 27c72fcc34Sopenharmony_ci{ 28c72fcc34Sopenharmony_ci gen->fd = open("/dev/urandom", O_RDONLY); 29c72fcc34Sopenharmony_ci if (gen->fd < 0) 30c72fcc34Sopenharmony_ci return -errno; 31c72fcc34Sopenharmony_ci 32c72fcc34Sopenharmony_ci gen->private_data = malloc(private_size); 33c72fcc34Sopenharmony_ci if (gen->private_data == NULL) 34c72fcc34Sopenharmony_ci return -ENOMEM; 35c72fcc34Sopenharmony_ci memset(gen->private_data, 0, private_size); 36c72fcc34Sopenharmony_ci 37c72fcc34Sopenharmony_ci gen->access_mask = access_mask; 38c72fcc34Sopenharmony_ci gen->sample_format_mask = sample_format_mask; 39c72fcc34Sopenharmony_ci gen->min_samples_per_frame = min_samples_per_frame; 40c72fcc34Sopenharmony_ci gen->max_samples_per_frame = max_samples_per_frame; 41c72fcc34Sopenharmony_ci gen->min_frame_count = min_frame_count; 42c72fcc34Sopenharmony_ci gen->max_frame_count = max_frame_count; 43c72fcc34Sopenharmony_ci gen->step_frame_count = step_frame_count; 44c72fcc34Sopenharmony_ci 45c72fcc34Sopenharmony_ci return 0; 46c72fcc34Sopenharmony_ci} 47c72fcc34Sopenharmony_ci 48c72fcc34Sopenharmony_cistatic void *allocate_buf(snd_pcm_access_t access, 49c72fcc34Sopenharmony_ci snd_pcm_format_t sample_format, 50c72fcc34Sopenharmony_ci unsigned int samples_per_frame, 51c72fcc34Sopenharmony_ci unsigned int frame_count) 52c72fcc34Sopenharmony_ci{ 53c72fcc34Sopenharmony_ci unsigned int bytes_per_sample; 54c72fcc34Sopenharmony_ci 55c72fcc34Sopenharmony_ci bytes_per_sample = snd_pcm_format_physical_width(sample_format) / 8; 56c72fcc34Sopenharmony_ci 57c72fcc34Sopenharmony_ci return calloc(samples_per_frame * frame_count, bytes_per_sample); 58c72fcc34Sopenharmony_ci} 59c72fcc34Sopenharmony_ci 60c72fcc34Sopenharmony_cistatic void *allocate_vector(snd_pcm_access_t access, 61c72fcc34Sopenharmony_ci snd_pcm_format_t sample_format, 62c72fcc34Sopenharmony_ci unsigned int samples_per_frame, 63c72fcc34Sopenharmony_ci unsigned int frame_count) 64c72fcc34Sopenharmony_ci{ 65c72fcc34Sopenharmony_ci unsigned int bytes_per_sample; 66c72fcc34Sopenharmony_ci char **bufs; 67c72fcc34Sopenharmony_ci int i; 68c72fcc34Sopenharmony_ci 69c72fcc34Sopenharmony_ci bytes_per_sample = snd_pcm_format_physical_width(sample_format) / 8; 70c72fcc34Sopenharmony_ci 71c72fcc34Sopenharmony_ci bufs = calloc(samples_per_frame, sizeof(char *)); 72c72fcc34Sopenharmony_ci if (bufs == NULL) 73c72fcc34Sopenharmony_ci return NULL; 74c72fcc34Sopenharmony_ci 75c72fcc34Sopenharmony_ci for (i = 0; i < samples_per_frame; ++i) { 76c72fcc34Sopenharmony_ci bufs[i] = calloc(frame_count, bytes_per_sample); 77c72fcc34Sopenharmony_ci if (bufs[i] == NULL) { 78c72fcc34Sopenharmony_ci for (; i >= 0; --i) 79c72fcc34Sopenharmony_ci free(bufs[i]); 80c72fcc34Sopenharmony_ci free(bufs); 81c72fcc34Sopenharmony_ci return NULL; 82c72fcc34Sopenharmony_ci } 83c72fcc34Sopenharmony_ci } 84c72fcc34Sopenharmony_ci 85c72fcc34Sopenharmony_ci return bufs; 86c72fcc34Sopenharmony_ci} 87c72fcc34Sopenharmony_ci 88c72fcc34Sopenharmony_cistatic int fill_buf(int fd, void *frame_buffer, snd_pcm_access_t access, 89c72fcc34Sopenharmony_ci snd_pcm_format_t sample_format, 90c72fcc34Sopenharmony_ci unsigned int samples_per_frame, unsigned int frame_count) 91c72fcc34Sopenharmony_ci{ 92c72fcc34Sopenharmony_ci unsigned int size; 93c72fcc34Sopenharmony_ci int len; 94c72fcc34Sopenharmony_ci 95c72fcc34Sopenharmony_ci size = snd_pcm_format_physical_width(sample_format) / 8 * 96c72fcc34Sopenharmony_ci samples_per_frame * frame_count; 97c72fcc34Sopenharmony_ci while (size > 0) { 98c72fcc34Sopenharmony_ci len = read(fd, frame_buffer, size); 99c72fcc34Sopenharmony_ci if (len < 0) 100c72fcc34Sopenharmony_ci return len; 101c72fcc34Sopenharmony_ci size -= len; 102c72fcc34Sopenharmony_ci } 103c72fcc34Sopenharmony_ci 104c72fcc34Sopenharmony_ci return 0; 105c72fcc34Sopenharmony_ci} 106c72fcc34Sopenharmony_ci 107c72fcc34Sopenharmony_cistatic int fill_vector(int fd, void *frame_buffer, snd_pcm_access_t access, 108c72fcc34Sopenharmony_ci snd_pcm_format_t sample_format, 109c72fcc34Sopenharmony_ci unsigned int samples_per_frame, unsigned int frame_count) 110c72fcc34Sopenharmony_ci{ 111c72fcc34Sopenharmony_ci char **bufs = frame_buffer; 112c72fcc34Sopenharmony_ci unsigned int size; 113c72fcc34Sopenharmony_ci int len; 114c72fcc34Sopenharmony_ci int i; 115c72fcc34Sopenharmony_ci 116c72fcc34Sopenharmony_ci for (i = 0; i < samples_per_frame; ++i) { 117c72fcc34Sopenharmony_ci size = frame_count * 118c72fcc34Sopenharmony_ci snd_pcm_format_physical_width(sample_format) / 8; 119c72fcc34Sopenharmony_ci 120c72fcc34Sopenharmony_ci while (size > 0) { 121c72fcc34Sopenharmony_ci len = read(fd, bufs[i], size); 122c72fcc34Sopenharmony_ci if (len < 0) 123c72fcc34Sopenharmony_ci return len; 124c72fcc34Sopenharmony_ci size -= len; 125c72fcc34Sopenharmony_ci } 126c72fcc34Sopenharmony_ci } 127c72fcc34Sopenharmony_ci 128c72fcc34Sopenharmony_ci return 0; 129c72fcc34Sopenharmony_ci} 130c72fcc34Sopenharmony_ci 131c72fcc34Sopenharmony_cistatic void deallocate_buf(void *frame_buffer, unsigned int samples_per_frame) 132c72fcc34Sopenharmony_ci{ 133c72fcc34Sopenharmony_ci free(frame_buffer); 134c72fcc34Sopenharmony_ci} 135c72fcc34Sopenharmony_ci 136c72fcc34Sopenharmony_cistatic void deallocate_vector(void *frame_buffer, 137c72fcc34Sopenharmony_ci unsigned int samples_per_frame) 138c72fcc34Sopenharmony_ci{ 139c72fcc34Sopenharmony_ci char **bufs = frame_buffer; 140c72fcc34Sopenharmony_ci int i; 141c72fcc34Sopenharmony_ci 142c72fcc34Sopenharmony_ci for (i = 0; i < samples_per_frame; ++i) 143c72fcc34Sopenharmony_ci free(bufs[i]); 144c72fcc34Sopenharmony_ci 145c72fcc34Sopenharmony_ci free(bufs); 146c72fcc34Sopenharmony_ci} 147c72fcc34Sopenharmony_ci 148c72fcc34Sopenharmony_cistatic int test_frame_count(struct test_generator *gen, 149c72fcc34Sopenharmony_ci snd_pcm_access_t access, 150c72fcc34Sopenharmony_ci snd_pcm_format_t sample_format, 151c72fcc34Sopenharmony_ci unsigned int samples_per_frame) 152c72fcc34Sopenharmony_ci{ 153c72fcc34Sopenharmony_ci void *(*allocator)(snd_pcm_access_t access, 154c72fcc34Sopenharmony_ci snd_pcm_format_t sample_format, 155c72fcc34Sopenharmony_ci unsigned int samples_per_frame, 156c72fcc34Sopenharmony_ci unsigned int frame_count); 157c72fcc34Sopenharmony_ci int (*fill)(int fd, void *frame_buffer, snd_pcm_access_t access, 158c72fcc34Sopenharmony_ci snd_pcm_format_t sample_format, 159c72fcc34Sopenharmony_ci unsigned int samples_per_frame, unsigned int frame_count); 160c72fcc34Sopenharmony_ci void (*deallocator)(void *frame_buffer, unsigned int samples_per_frame); 161c72fcc34Sopenharmony_ci void *frame_buffer; 162c72fcc34Sopenharmony_ci int i; 163c72fcc34Sopenharmony_ci int err = 0; 164c72fcc34Sopenharmony_ci 165c72fcc34Sopenharmony_ci if (access != SND_PCM_ACCESS_RW_NONINTERLEAVED) { 166c72fcc34Sopenharmony_ci allocator = allocate_buf; 167c72fcc34Sopenharmony_ci fill = fill_buf; 168c72fcc34Sopenharmony_ci deallocator = deallocate_buf; 169c72fcc34Sopenharmony_ci } else { 170c72fcc34Sopenharmony_ci allocator = allocate_vector; 171c72fcc34Sopenharmony_ci fill = fill_vector; 172c72fcc34Sopenharmony_ci deallocator = deallocate_vector; 173c72fcc34Sopenharmony_ci } 174c72fcc34Sopenharmony_ci 175c72fcc34Sopenharmony_ci frame_buffer = allocator(access, sample_format, samples_per_frame, 176c72fcc34Sopenharmony_ci gen->max_frame_count); 177c72fcc34Sopenharmony_ci if (frame_buffer == NULL) 178c72fcc34Sopenharmony_ci return -ENOMEM; 179c72fcc34Sopenharmony_ci 180c72fcc34Sopenharmony_ci err = fill(gen->fd, frame_buffer, access, sample_format, 181c72fcc34Sopenharmony_ci samples_per_frame, gen->max_frame_count); 182c72fcc34Sopenharmony_ci if (err < 0) 183c72fcc34Sopenharmony_ci goto end; 184c72fcc34Sopenharmony_ci 185c72fcc34Sopenharmony_ci 186c72fcc34Sopenharmony_ci for (i = gen->min_frame_count; 187c72fcc34Sopenharmony_ci i <= gen->max_frame_count; i += gen->step_frame_count) { 188c72fcc34Sopenharmony_ci err = gen->cb(gen, access ,sample_format, samples_per_frame, 189c72fcc34Sopenharmony_ci frame_buffer, i); 190c72fcc34Sopenharmony_ci if (err < 0) 191c72fcc34Sopenharmony_ci break; 192c72fcc34Sopenharmony_ci } 193c72fcc34Sopenharmony_ciend: 194c72fcc34Sopenharmony_ci deallocator(frame_buffer, samples_per_frame); 195c72fcc34Sopenharmony_ci 196c72fcc34Sopenharmony_ci return err; 197c72fcc34Sopenharmony_ci} 198c72fcc34Sopenharmony_ci 199c72fcc34Sopenharmony_cistatic int test_samples_per_frame(struct test_generator *gen, 200c72fcc34Sopenharmony_ci snd_pcm_access_t access, 201c72fcc34Sopenharmony_ci snd_pcm_format_t sample_format) 202c72fcc34Sopenharmony_ci{ 203c72fcc34Sopenharmony_ci int i; 204c72fcc34Sopenharmony_ci int err = 0; 205c72fcc34Sopenharmony_ci 206c72fcc34Sopenharmony_ci for (i = gen->min_samples_per_frame; 207c72fcc34Sopenharmony_ci i <= gen->max_samples_per_frame; ++i) { 208c72fcc34Sopenharmony_ci err = test_frame_count(gen, access, sample_format, i); 209c72fcc34Sopenharmony_ci if (err < 0) 210c72fcc34Sopenharmony_ci break; 211c72fcc34Sopenharmony_ci } 212c72fcc34Sopenharmony_ci 213c72fcc34Sopenharmony_ci return err; 214c72fcc34Sopenharmony_ci} 215c72fcc34Sopenharmony_ci 216c72fcc34Sopenharmony_cistatic int test_sample_format(struct test_generator *gen, 217c72fcc34Sopenharmony_ci snd_pcm_access_t access) 218c72fcc34Sopenharmony_ci{ 219c72fcc34Sopenharmony_ci int i; 220c72fcc34Sopenharmony_ci int err = 0; 221c72fcc34Sopenharmony_ci 222c72fcc34Sopenharmony_ci for (i = 0; i <= SND_PCM_FORMAT_LAST; ++i) { 223c72fcc34Sopenharmony_ci if (!((1ull << i) & gen->sample_format_mask)) 224c72fcc34Sopenharmony_ci continue; 225c72fcc34Sopenharmony_ci 226c72fcc34Sopenharmony_ci err = test_samples_per_frame(gen, access, i); 227c72fcc34Sopenharmony_ci if (err < 0) 228c72fcc34Sopenharmony_ci break; 229c72fcc34Sopenharmony_ci } 230c72fcc34Sopenharmony_ci 231c72fcc34Sopenharmony_ci return err; 232c72fcc34Sopenharmony_ci} 233c72fcc34Sopenharmony_ci 234c72fcc34Sopenharmony_cistatic int test_access(struct test_generator *gen) 235c72fcc34Sopenharmony_ci{ 236c72fcc34Sopenharmony_ci int i; 237c72fcc34Sopenharmony_ci int err = 0; 238c72fcc34Sopenharmony_ci 239c72fcc34Sopenharmony_ci for (i = 0; i <= SND_PCM_ACCESS_LAST; ++i) { 240c72fcc34Sopenharmony_ci if (!((1ull << i) & gen->access_mask)) 241c72fcc34Sopenharmony_ci continue; 242c72fcc34Sopenharmony_ci 243c72fcc34Sopenharmony_ci err = test_sample_format(gen, i); 244c72fcc34Sopenharmony_ci if (err < 0) 245c72fcc34Sopenharmony_ci break; 246c72fcc34Sopenharmony_ci } 247c72fcc34Sopenharmony_ci return err; 248c72fcc34Sopenharmony_ci} 249c72fcc34Sopenharmony_ci 250c72fcc34Sopenharmony_ciint generator_context_run(struct test_generator *gen, generator_cb_t cb) 251c72fcc34Sopenharmony_ci{ 252c72fcc34Sopenharmony_ci gen->cb = cb; 253c72fcc34Sopenharmony_ci return test_access(gen); 254c72fcc34Sopenharmony_ci} 255c72fcc34Sopenharmony_ci 256c72fcc34Sopenharmony_civoid generator_context_destroy(struct test_generator *gen) 257c72fcc34Sopenharmony_ci{ 258c72fcc34Sopenharmony_ci free(gen->private_data); 259c72fcc34Sopenharmony_ci close(gen->fd); 260c72fcc34Sopenharmony_ci} 261