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