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