1 /*
2 * Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved.
3 *
4 * Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in
5 * the the people's Republic of China and other countries.
6 * All Allwinner Technology Co.,Ltd. trademarks are used with permission.
7 *
8 * DISCLAIMER
9 * THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT.
10 * IF YOU NEED TO INTEGRATE THIRD PARTY’S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.)
11 * IN ALLWINNERS’SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN
12 * ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES.
13 * ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS
14 * COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE.
15 * YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY’S TECHNOLOGY.
16 *
17 *
18 * THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT
19 * PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND,
20 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING
21 * THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE
22 * OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 * IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 #include <sound/ksound.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <errno.h>
37 #include <aw-alsa-lib/pcm.h>
38 #include <aw-alsa-lib/pcm_config.h>
39 #include "pcm_local.h"
40 #include <hal_osal.h>
snd_pcm_version(void)41 void snd_pcm_version(void)
42 {
43 #ifdef CONFIG_KERNEL_FREERTOS
44 printf("AW-ALSA-LIB version:%s, compiled on: %s %s\n\n",
45 SND_PCM_VERSION, __DATE__, __TIME__);
46 #else
47 printf("AW-ALSA-LIB version:%s\n", SND_PCM_VERSION);
48 #endif
49 }
50
snd_pcm_hw_params_sizeof(void)51 size_t snd_pcm_hw_params_sizeof(void)
52 {
53 return sizeof(snd_pcm_hw_params_t);
54 }
55
snd_pcm_sw_params_sizeof(void)56 size_t snd_pcm_sw_params_sizeof(void)
57 {
58 return sizeof(snd_pcm_sw_params_t);
59 }
60
snd_pcm_link_ptr(snd_pcm_t * pcm,snd_pcm_rbptr_t * pcm_rbptr,snd_pcm_t * slave,snd_pcm_rbptr_t * slave_rbptr)61 static void snd_pcm_link_ptr(snd_pcm_t *pcm, snd_pcm_rbptr_t *pcm_rbptr,
62 snd_pcm_t *slave, snd_pcm_rbptr_t *slave_rbptr)
63 {
64 snd_pcm_t **a, **newa;
65 int idx;
66
67 a = slave_rbptr->link_dst;
68 for (idx = 0; idx < slave_rbptr->link_dst_count; idx++) {
69 if (a[idx] == NULL) {
70 a[idx] = pcm;
71 goto __found_free_place;
72 }
73 }
74 newa = realloc(a, sizeof(snd_pcm_t *) * (slave_rbptr->link_dst_count + 1));
75 if (newa == NULL) {
76 pcm_rbptr->ptr = NULL;
77 pcm_rbptr->offset = 0UL;
78 free(a);
79 return;
80 }
81 a = newa;
82 a[slave_rbptr->link_dst_count++] = pcm;
83 __found_free_place:
84 pcm_rbptr->master = slave_rbptr->master ? slave_rbptr->master : slave;
85 pcm_rbptr->ptr = slave_rbptr->ptr;
86 pcm_rbptr->offset = slave_rbptr->offset;
87 slave_rbptr->link_dst = a;
88 }
89
snd_pcm_unlink_ptr(snd_pcm_t * pcm,snd_pcm_rbptr_t * pcm_rbptr,snd_pcm_t * slave,snd_pcm_rbptr_t * slave_rbptr)90 static void snd_pcm_unlink_ptr(snd_pcm_t *pcm, snd_pcm_rbptr_t *pcm_rbptr,
91 snd_pcm_t *slave, snd_pcm_rbptr_t *slave_rbptr)
92 {
93 snd_pcm_t **a;
94 int idx;
95
96 a = slave_rbptr->link_dst;
97 for (idx = 0; idx < slave_rbptr->link_dst_count; idx++) {
98 if (a[idx] == pcm) {
99 a[idx] = NULL;
100 goto __found;
101 }
102 }
103 /* assert(0); */
104 return;
105
106 __found:
107 pcm_rbptr->master = NULL;
108 pcm_rbptr->ptr = NULL;
109 pcm_rbptr->offset = 0UL;
110 }
111
snd_pcm_set_ptr(snd_pcm_t * pcm,snd_pcm_rbptr_t * rbptr,volatile snd_pcm_uframes_t * ptr,int fd,off_t offset)112 static void snd_pcm_set_ptr(snd_pcm_t *pcm, snd_pcm_rbptr_t *rbptr,
113 volatile snd_pcm_uframes_t *ptr, int fd, off_t offset)
114 {
115 rbptr->ptr = ptr;
116 }
117
snd_pcm_link_hw_ptr(snd_pcm_t * pcm,snd_pcm_t * slave)118 void snd_pcm_link_hw_ptr(snd_pcm_t *pcm, snd_pcm_t *slave)
119 {
120 assert(pcm);
121 assert(slave);
122 snd_pcm_link_ptr(pcm, &pcm->hw, slave, &slave->hw);
123 }
124
snd_pcm_link_appl_ptr(snd_pcm_t * pcm,snd_pcm_t * slave)125 void snd_pcm_link_appl_ptr(snd_pcm_t *pcm, snd_pcm_t *slave)
126 {
127 assert(pcm);
128 assert(slave);
129 snd_pcm_link_ptr(pcm, &pcm->appl, slave, &slave->appl);
130 }
131
snd_pcm_unlink_hw_ptr(snd_pcm_t * pcm,snd_pcm_t * slave)132 void snd_pcm_unlink_hw_ptr(snd_pcm_t *pcm, snd_pcm_t *slave)
133 {
134 assert(pcm);
135 assert(slave);
136 snd_pcm_unlink_ptr(pcm, &pcm->hw, slave, &slave->hw);
137 }
138
snd_pcm_unlink_appl_ptr(snd_pcm_t * pcm,snd_pcm_t * slave)139 void snd_pcm_unlink_appl_ptr(snd_pcm_t *pcm, snd_pcm_t *slave)
140 {
141 assert(pcm);
142 assert(slave);
143 snd_pcm_unlink_ptr(pcm, &pcm->appl, slave, &slave->appl);
144 }
145
146 /* fd and offset are not used */
snd_pcm_set_hw_ptr(snd_pcm_t * pcm,volatile snd_pcm_uframes_t * hw_ptr,int fd,off_t offset)147 void snd_pcm_set_hw_ptr(snd_pcm_t *pcm, volatile snd_pcm_uframes_t *hw_ptr,
148 int fd, off_t offset)
149 {
150 assert(pcm);
151 assert(hw_ptr);
152 snd_pcm_set_ptr(pcm, &pcm->hw, hw_ptr, fd, offset);
153 }
154
155 /* fd and offset are not used */
snd_pcm_set_appl_ptr(snd_pcm_t * pcm,volatile snd_pcm_uframes_t * appl_ptr,int fd,off_t offset)156 void snd_pcm_set_appl_ptr(snd_pcm_t *pcm, volatile snd_pcm_uframes_t *appl_ptr,
157 int fd, off_t offset)
158 {
159 assert(pcm);
160 assert(appl_ptr);
161 snd_pcm_set_ptr(pcm, &pcm->appl, appl_ptr, fd, offset);
162 }
163
snd_pcm_open_config(snd_pcm_t ** pcmp,const snd_pcm_config_t * pcm_config,snd_pcm_stream_t stream,int mode)164 int snd_pcm_open_config(snd_pcm_t **pcmp, const snd_pcm_config_t *pcm_config,
165 snd_pcm_stream_t stream, int mode)
166 {
167 snd_pcm_open_func_t open_func = NULL;
168
169 open_func = snd_pcm_config_get_open_func(pcm_config->type);
170 if (!open_func) {
171 awalsa_err("open_func of type \"%s\" not found\n", pcm_config->type);
172 return -ENODEV;
173 }
174
175 return open_func(pcmp, pcm_config, stream, mode);
176 }
177
snd_pcm_open(snd_pcm_t ** pcm,const char * name,snd_pcm_stream_t stream,int mode)178 int snd_pcm_open(snd_pcm_t **pcm, const char *name,
179 snd_pcm_stream_t stream, int mode)
180 {
181 int ret = 0, res = 0;
182
183 const snd_pcm_config_t *top_config = NULL;
184 top_config = snd_pcm_config_get_config(name);
185 if (!top_config) {
186 awalsa_err("pcm \"%s\": config not found\n", name);
187 res = -1;
188 goto out;
189 }
190
191 ret = snd_pcm_open_config(pcm, top_config, stream, mode);
192 if (0 != ret) {
193 awalsa_err("pcm \"%s\": snd_pcm_open_config failed (return: %d)\n", name, ret);
194 res = ret;
195 goto out;
196 }
197
198 out:
199 return res;
200 }
201
snd_pcm_close(snd_pcm_t * pcm)202 int snd_pcm_close(snd_pcm_t *pcm)
203 {
204 int ret = 0, res = 0;
205
206 assert(pcm);
207 awalsa_debug("\n");
208 if (pcm->setup && !pcm->donot_close) {
209 snd_pcm_drop(pcm);
210 ret = snd_pcm_hw_free(pcm);
211 if (ret < 0)
212 res = ret;
213 }
214 if (pcm->mmap_channels)
215 snd_pcm_munmap(pcm);
216 assert(pcm->ops->close);
217 ret = pcm->ops->close(pcm->op_arg);
218 if (ret < 0)
219 res = ret;
220 ret = snd_pcm_free(pcm);
221 if (ret < 0)
222 res = ret;
223
224 return res;
225 }
226
snd_pcm_hw_params_malloc(snd_pcm_hw_params_t ** ptr)227 int snd_pcm_hw_params_malloc(snd_pcm_hw_params_t **ptr)
228 {
229 assert(ptr);
230 *ptr = calloc(1, sizeof(snd_pcm_hw_params_t));
231 if (!*ptr)
232 return -ENOMEM;
233 return 0;
234 }
235
snd_pcm_hw_params_free(snd_pcm_hw_params_t * obj)236 void snd_pcm_hw_params_free(snd_pcm_hw_params_t *obj)
237 {
238 free(obj);
239 }
240
snd_pcm_hw_params_any(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)241 int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
242 {
243 assert(pcm);
244 awalsa_debug("\n");
245 assert(pcm->ops->hw_refine);
246 _snd_pcm_hw_params_any(params);
247 return snd_pcm_hw_refine(pcm,params);
248 }
249
250 #if 0
251 int snd_interval_refine(snd_interval_t *i, const snd_interval_t *v)
252 {
253 int changed = 0;
254
255 if (i->range.min < v->range.min) {
256 i->range.min = v->range.min;
257 changed = 1;
258 }
259 if (i->range.max > v->range.max) {
260 i->range.max = v->range.max;
261 changed = 1;
262 }
263 if (i->mask != v->mask) {
264 i->mask = v->mask;
265 changed = 1;
266 }
267 return changed;
268 }
269
270 int hw_param_interval_refine_one(snd_pcm_hw_params_t *params,
271 snd_pcm_hw_param_t var,
272 snd_interval_t *src)
273 {
274
275 }
276 #endif
277
snd_pcm_hw_params_set_format(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_format_t format)278 int snd_pcm_hw_params_set_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t format)
279 {
280 awalsa_debug("\n");
281 return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_FORMAT, format, 0);
282 }
283
snd_pcm_hw_params_set_rate(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,unsigned int val,int dir)284 int snd_pcm_hw_params_set_rate(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir)
285 {
286 awalsa_debug("\n");
287 return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_RATE, val, dir);
288 }
289
snd_pcm_hw_params_set_period_size(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_uframes_t val,int dir)290 int snd_pcm_hw_params_set_period_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir)
291 {
292 awalsa_debug("\n");
293 return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIOD_SIZE, val, dir);
294 }
295
snd_pcm_hw_params_set_period_size_near(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_uframes_t * val,int * dir)296 int snd_pcm_hw_params_set_period_size_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir)
297 {
298 awalsa_debug("\n");
299 unsigned int _val = *val;
300 int err = snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_PERIOD_SIZE, &_val, dir);
301 if (err >= 0)
302 *val = _val;
303 return err;
304 }
305
snd_pcm_hw_params_set_period_time(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,unsigned int us,int dir)306 int snd_pcm_hw_params_set_period_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int us, int dir)
307 {
308 awalsa_debug("\n");
309 return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIOD_TIME, us, dir);
310 }
311
snd_pcm_hw_params_set_period_time_near(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,unsigned int * val,int * dir)312 int snd_pcm_hw_params_set_period_time_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
313 {
314 awalsa_debug("\n");
315 return snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, val, dir);
316 }
317
snd_pcm_hw_params_set_buffer_size(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_uframes_t val)318 int snd_pcm_hw_params_set_buffer_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val)
319 {
320 awalsa_debug("\n");
321 return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_BUFFER_SIZE, val, 0);
322 }
323
snd_pcm_hw_params_set_buffer_size_near(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_uframes_t * val)324 int snd_pcm_hw_params_set_buffer_size_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)
325 {
326 awalsa_debug("\n");
327 unsigned int _val = *val;
328 int err = snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, &_val, NULL);
329 if (err >= 0)
330 *val = _val;
331 return err;
332 }
333
snd_pcm_hw_params_set_buffer_time(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,unsigned int us)334 int snd_pcm_hw_params_set_buffer_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int us)
335 {
336 awalsa_debug("\n");
337 return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_BUFFER_TIME, us, 0);
338 }
339
snd_pcm_hw_params_set_buffer_time_near(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,unsigned int * val,int * dir)340 int snd_pcm_hw_params_set_buffer_time_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
341 {
342 awalsa_debug("\n");
343 return snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_BUFFER_TIME, val, dir);
344 }
345
snd_pcm_hw_params_set_channels(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,unsigned int val)346 int snd_pcm_hw_params_set_channels(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val)
347 {
348 awalsa_debug("\n");
349 return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_CHANNELS, val, 0);
350 }
351
snd_pcm_hw_params_set_periods(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,unsigned int val,int dir)352 int snd_pcm_hw_params_set_periods(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir)
353 {
354 awalsa_debug("\n");
355 return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIODS, val, dir);
356 }
357
snd_pcm_hw_params_set_periods_near(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,unsigned int * val,int * dir)358 int snd_pcm_hw_params_set_periods_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
359 {
360 awalsa_debug("\n");
361 return snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_PERIODS, val, dir);
362 }
363
snd_pcm_hw_params_set_access(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_access_t access)364 int snd_pcm_hw_params_set_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t access)
365 {
366 awalsa_debug("\n");
367 return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_ACCESS, access, 0);
368 }
369
snd_pcm_hw_params_get_access(const snd_pcm_hw_params_t * params,snd_pcm_access_t * access)370 int snd_pcm_hw_params_get_access(const snd_pcm_hw_params_t *params, snd_pcm_access_t *access)
371 {
372 unsigned int _val;
373 int err = snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_ACCESS, &_val, NULL);
374 if (err >= 0)
375 *access = _val;
376 return err;
377 }
378
snd_pcm_hw_params_get_format(const snd_pcm_hw_params_t * params,snd_pcm_format_t * format)379 int snd_pcm_hw_params_get_format(const snd_pcm_hw_params_t *params, snd_pcm_format_t *format)
380 {
381 unsigned int _val;
382 int err = snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_FORMAT, &_val, NULL);
383 if (err >= 0)
384 *format = _val;
385 return err;
386 }
387
snd_pcm_hw_params_get_channels(const snd_pcm_hw_params_t * params,unsigned int * val)388 int snd_pcm_hw_params_get_channels(const snd_pcm_hw_params_t *params, unsigned int *val)
389 {
390 return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_CHANNELS, val, NULL);
391 }
392
snd_pcm_hw_params_get_rate(const snd_pcm_hw_params_t * params,unsigned int * val,int * dir)393 int snd_pcm_hw_params_get_rate(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
394 {
395 return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_RATE, val, dir);
396 }
397
snd_pcm_hw_params_get_period_time(const snd_pcm_hw_params_t * params,unsigned int * val,int * dir)398 int snd_pcm_hw_params_get_period_time(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
399 {
400 return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_PERIOD_TIME, val, dir);
401 }
402
snd_pcm_hw_params_get_period_size(const snd_pcm_hw_params_t * params,snd_pcm_uframes_t * val,int * dir)403 int snd_pcm_hw_params_get_period_size(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir)
404 {
405 unsigned int _val;
406 int err = snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_PERIOD_SIZE, &_val, dir);
407 if (err >= 0)
408 *val = _val;
409 return err;
410 }
411
snd_pcm_hw_params_get_buffer_size(const snd_pcm_hw_params_t * params,snd_pcm_uframes_t * val)412 int snd_pcm_hw_params_get_buffer_size(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)
413 {
414 unsigned int _val;
415 int err = snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &_val, NULL);
416 if (err >= 0)
417 *val = _val;
418 return err;
419 }
420
snd_pcm_hw_params_get_buffer_time(const snd_pcm_hw_params_t * params,unsigned int * val,int * dir)421 int snd_pcm_hw_params_get_buffer_time(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
422 {
423 return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_BUFFER_TIME, val, dir);
424 }
425
snd_pcm_hw_params_get_periods(const snd_pcm_hw_params_t * params,unsigned int * val,int * dir)426 int snd_pcm_hw_params_get_periods(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
427 {
428 return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_PERIODS, val, dir);
429 }
430
snd_pcm_hw_params(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)431 int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
432 {
433 int ret;
434 assert(pcm && params);
435 awalsa_debug("\n");
436 ret = _snd_pcm_hw_params_internal(pcm, params);
437 if (ret < 0)
438 return ret;
439 ret = snd_pcm_prepare(pcm);
440 return ret;
441 }
442
snd_pcm_hw_free(snd_pcm_t * pcm)443 int snd_pcm_hw_free(snd_pcm_t *pcm)
444 {
445 int ret;
446 assert(pcm);
447 awalsa_debug("\n");
448
449 if (!pcm->setup)
450 return 0;
451 if (pcm->mmap_channels) {
452 ret = snd_pcm_munmap(pcm);
453 if (ret < 0)
454 return ret;
455 }
456
457 assert(pcm->ops->hw_free);
458 ret = pcm->ops->hw_free(pcm->op_arg);
459 pcm->setup = 0;
460
461 return ret;
462 }
463
snd_pcm_sw_params_current(snd_pcm_t * pcm,snd_pcm_sw_params_t * params)464 int snd_pcm_sw_params_current(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
465 {
466 assert(pcm && params);
467 params->avail_min = pcm->avail_min;
468 params->start_threshold = pcm->start_threshold;
469 params->stop_threshold = pcm->stop_threshold;
470 params->silence_size = pcm->silence_size;
471 params->boundary = pcm->boundary;
472 return 0;
473 }
474
snd_pcm_sw_params_set_start_threshold(snd_pcm_t * pcm,snd_pcm_sw_params_t * params,snd_pcm_uframes_t val)475 int snd_pcm_sw_params_set_start_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val)
476 {
477 assert(pcm && params);
478 params->start_threshold = val;
479 return 0;
480 }
481
snd_pcm_sw_params_get_start_threshold(snd_pcm_sw_params_t * params,snd_pcm_uframes_t * val)482 int snd_pcm_sw_params_get_start_threshold(snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val)
483 {
484 assert(params && val);
485 *val = params->start_threshold;
486 return 0;
487 }
488
snd_pcm_sw_params_set_stop_threshold(snd_pcm_t * pcm,snd_pcm_sw_params_t * params,snd_pcm_uframes_t val)489 int snd_pcm_sw_params_set_stop_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val)
490 {
491 assert(pcm && params);
492 params->stop_threshold = val;
493 return 0;
494 }
495
snd_pcm_sw_params_get_stop_threshold(snd_pcm_sw_params_t * params,snd_pcm_uframes_t * val)496 int snd_pcm_sw_params_get_stop_threshold(snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val)
497 {
498 assert(params && val);
499 *val = params->stop_threshold;
500 return 0;
501 }
502
snd_pcm_sw_params_set_silence_size(snd_pcm_t * pcm,snd_pcm_sw_params_t * params,snd_pcm_uframes_t val)503 int snd_pcm_sw_params_set_silence_size(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val)
504 {
505 assert(pcm && params);
506 params->silence_size = val;
507 return 0;
508 }
509
snd_pcm_sw_params_get_silence_size(snd_pcm_sw_params_t * params,snd_pcm_uframes_t * val)510 int snd_pcm_sw_params_get_silence_size(snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val)
511 {
512 assert(params && val);
513 *val = params->silence_size;
514 return 0;
515 }
516
snd_pcm_sw_params_set_avail_min(snd_pcm_t * pcm,snd_pcm_sw_params_t * params,snd_pcm_uframes_t val)517 int snd_pcm_sw_params_set_avail_min(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val)
518 {
519 assert(pcm && params);
520 params->avail_min = val;
521 return 0;
522 }
523
snd_pcm_sw_params_get_avail_min(const snd_pcm_sw_params_t * params,snd_pcm_uframes_t * val)524 int snd_pcm_sw_params_get_avail_min(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val)
525 {
526 assert(params && val);
527 *val = params->avail_min;
528 return 0;
529 }
530
snd_pcm_sw_params_get_boundary(const snd_pcm_sw_params_t * params,snd_pcm_uframes_t * val)531 int snd_pcm_sw_params_get_boundary(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val)
532 {
533 assert(params && val);
534 *val = params->boundary;
535 return 0;
536 }
537
snd_pcm_sw_params(snd_pcm_t * pcm,snd_pcm_sw_params_t * params)538 int snd_pcm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
539 {
540 int ret = 0;
541
542 assert(pcm && params);
543 /* the hw_params must be set at first!!! */
544 if (!pcm->setup) {
545 awalsa_err("PCM not set up\n");
546 return -EIO;
547 }
548 if (!params->avail_min) {
549 awalsa_err("params->avail_min is 0\n");
550 return -EINVAL;
551 }
552
553 assert(pcm->ops->sw_params);
554 snd_pcm_lock(pcm);
555 ret = pcm->ops->sw_params(pcm->op_arg, params);
556 if (ret < 0) {
557 snd_pcm_unlock(pcm);
558 return ret;
559 }
560 pcm->avail_min = params->avail_min;
561 pcm->start_threshold = params->start_threshold;
562 pcm->stop_threshold = params->stop_threshold;
563 pcm->silence_size = params->silence_size;
564 pcm->boundary = params->boundary;
565 snd_pcm_unlock(pcm);
566 return ret;
567 }
568
snd_pcm_prepare(snd_pcm_t * pcm)569 int snd_pcm_prepare(snd_pcm_t *pcm)
570 {
571 int ret = 0;
572
573 assert(pcm);
574 awalsa_debug("\n");
575
576 assert(pcm->fast_ops->prepare);
577 snd_pcm_lock(pcm);
578 ret = pcm->fast_ops->prepare(pcm->fast_op_arg);
579 snd_pcm_unlock(pcm);
580 return ret;
581 }
582
snd_pcm_reset(snd_pcm_t * pcm)583 int snd_pcm_reset(snd_pcm_t *pcm)
584 {
585 int err;
586
587 assert(pcm);
588 awalsa_debug("\n");
589
590 assert(pcm->fast_ops->reset);
591 if (! pcm->setup) {
592 awalsa_err("PCM not set up\n");
593 return -EIO;
594 }
595 snd_pcm_lock(pcm);
596 err = pcm->fast_ops->reset(pcm->fast_op_arg);
597 snd_pcm_unlock(pcm);
598 return err;
599 }
600
snd_pcm_start(snd_pcm_t * pcm)601 int snd_pcm_start(snd_pcm_t *pcm)
602 {
603 int ret = 0;
604
605 assert(pcm);
606 awalsa_debug("\n");
607
608 assert(pcm->fast_ops->start);
609 snd_pcm_lock(pcm);
610 ret = pcm->fast_ops->start(pcm->fast_op_arg);
611 snd_pcm_unlock(pcm);
612 return ret;
613 }
614
snd_pcm_drop(snd_pcm_t * pcm)615 int snd_pcm_drop(snd_pcm_t *pcm)
616 {
617 int ret = 0;
618
619 assert(pcm);
620 awalsa_debug("\n");
621
622 assert(pcm->fast_ops->drop);
623 snd_pcm_lock(pcm);
624 ret = pcm->fast_ops->drop(pcm->fast_op_arg);
625 snd_pcm_unlock(pcm);
626 return ret;
627 }
628
snd_pcm_drain(snd_pcm_t * pcm)629 int snd_pcm_drain(snd_pcm_t *pcm)
630 {
631 assert(pcm);
632 awalsa_debug("\n");
633
634 assert(pcm->fast_ops->drain);
635 /* do not lock. lock is handled in the callback */
636 return pcm->fast_ops->drain(pcm->fast_op_arg);
637 }
638
snd_pcm_pause(snd_pcm_t * pcm,int enable)639 int snd_pcm_pause(snd_pcm_t *pcm, int enable)
640 {
641 int ret = 0;
642
643 assert(pcm);
644 awalsa_debug("\n");
645
646 assert(pcm->fast_ops->pause);
647 snd_pcm_lock(pcm);
648 ret = pcm->fast_ops->pause(pcm->fast_op_arg, enable);
649 snd_pcm_unlock(pcm);
650 return ret;
651 }
652
snd_pcm_state(snd_pcm_t * pcm)653 snd_pcm_state_t snd_pcm_state(snd_pcm_t *pcm)
654 {
655 snd_pcm_state_t state;
656
657 assert(pcm);
658 awalsa_debug("\n");
659
660 assert(pcm->fast_ops->state);
661 snd_pcm_lock(pcm);
662 state = pcm->fast_ops->state(pcm->fast_op_arg);
663 snd_pcm_unlock(pcm);
664
665 return state;
666 }
667
snd_pcm_hwsync(snd_pcm_t * pcm)668 int snd_pcm_hwsync(snd_pcm_t *pcm)
669 {
670 int err;
671
672 assert(pcm);
673 if (!pcm->setup) {
674 awalsa_err("PCM not set up\n");
675 return -EIO;
676 }
677 snd_pcm_lock(pcm);
678 err = __snd_pcm_hwsync(pcm);
679 snd_pcm_unlock(pcm);
680 return err;
681 }
682
snd_pcm_stream(snd_pcm_t * pcm)683 snd_pcm_stream_t snd_pcm_stream(snd_pcm_t *pcm)
684 {
685 assert(pcm);
686 return pcm->stream;
687 }
688
snd_pcm_writei(snd_pcm_t * pcm,const void * buffer,snd_pcm_uframes_t size)689 snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
690 {
691 snd_pcm_sframes_t ret = 0;
692
693 assert(pcm);
694 assert(size == 0 || buffer);
695 /*awalsa_debug("\n");*/
696 ret = pcm->fast_ops->writei(pcm->fast_op_arg, buffer, size);
697
698 return ret;
699 }
700
snd_pcm_readi(snd_pcm_t * pcm,void * buffer,snd_pcm_uframes_t size)701 snd_pcm_sframes_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
702 {
703
704 snd_pcm_sframes_t ret = 0;
705
706 assert(pcm);
707 assert(size == 0 || buffer);
708 awalsa_debug("\n");
709 ret = pcm->fast_ops->readi(pcm->fast_op_arg, buffer, size);
710
711 return ret;
712 }
713
snd_pcm_resume(snd_pcm_t * pcm)714 int snd_pcm_resume(snd_pcm_t *pcm)
715 {
716 assert(pcm);
717 awalsa_err("suspend state not supported.\n");
718 return -1;
719 }
720
snd_pcm_recover(snd_pcm_t * pcm,int err,int silent)721 int snd_pcm_recover(snd_pcm_t *pcm, int err, int silent)
722 {
723 assert(pcm);
724 if (err > 0)
725 err = -err;
726 if (err == -EPIPE) {
727 const char *s = NULL;
728 if (snd_pcm_stream(pcm) == SND_PCM_STREAM_PLAYBACK)
729 s = "underrun";
730 else
731 s = "overrun";
732 if (!silent)
733 awalsa_err("%s occured\n", s);
734 err = snd_pcm_prepare(pcm);
735 if (err < 0) {
736 awalsa_err("cannot recovery from %s, prepare return: %d",
737 s, err);
738 return err;
739 }
740 return 0;
741 }
742 if (err == -ESTRPIPE) {
743 awalsa_info("resume...\n");
744 while ((err = snd_pcm_resume(pcm)) == -EAGAIN)
745 hal_usleep(1000);
746 if (err < 0) {
747 err = snd_pcm_prepare(pcm);
748 awalsa_err("cannot recovery from suspend, prepare return: %d", err);
749 return err;
750 }
751 return 0;
752 }
753 return err;
754 }
755
snd_pcm_delay(snd_pcm_t * pcm,snd_pcm_sframes_t * delayp)756 int snd_pcm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
757 {
758 int ret = 0;
759
760 assert(pcm);
761 assert(delayp);
762
763 snd_pcm_lock(pcm);
764 ret = pcm->fast_ops->delay(pcm->fast_op_arg, delayp);
765 snd_pcm_unlock(pcm);
766
767 return ret;
768 }
769
snd_pcm_dump_hw_setup(snd_pcm_t * pcm)770 int snd_pcm_dump_hw_setup(snd_pcm_t *pcm)
771 {
772 assert(pcm);
773 if (!pcm->setup) {
774 awalsa_err("PCM not set up\n");
775 return -EIO;
776 }
777 printf(" stream : %s\n", snd_pcm_stream_name(pcm->stream));
778 printf(" access : %s\n", snd_pcm_access_name(pcm->access));
779 printf(" format : %s\n", snd_pcm_format_name(pcm->format));
780 printf(" channels : %u\n", pcm->channels);
781 printf(" rate : %u\n", pcm->rate);
782 printf(" buffer_size : %lu\n", pcm->buffer_size);
783 printf(" period_size : %lu\n", pcm->period_size);
784 printf(" period_time : %u\n", pcm->period_time);
785 return 0;
786 }
787
snd_pcm_dump_sw_setup(snd_pcm_t * pcm)788 int snd_pcm_dump_sw_setup(snd_pcm_t *pcm)
789 {
790 assert(pcm);
791 if (!pcm->setup) {
792 awalsa_err("PCM not set up\n");
793 return -EIO;
794 }
795 printf(" avail_min : %lu\n", pcm->avail_min);
796 printf(" start_threshold : %lu\n", pcm->start_threshold);
797 printf(" stop_threshold : %lu\n", pcm->stop_threshold);
798 printf(" silence_size : %lu\n", pcm->silence_size);
799 printf(" boundary : %lu\n", pcm->boundary);
800 return 0;
801 }
802
snd_pcm_dump_setup(snd_pcm_t * pcm)803 int snd_pcm_dump_setup(snd_pcm_t *pcm)
804 {
805 snd_pcm_dump_hw_setup(pcm);
806 snd_pcm_dump_sw_setup(pcm);
807 return 0;
808 }
809
snd_pcm_dump(snd_pcm_t * pcm)810 int snd_pcm_dump(snd_pcm_t *pcm)
811 {
812 assert(pcm);
813 if (pcm->ops->dump)
814 pcm->ops->dump(pcm->op_arg);
815 else
816 printf("pcm:%s not support dump.\n", pcm->name);
817 return 0;
818 }
819
dump_one_param(snd_pcm_hw_params_t * params,unsigned int k)820 static void dump_one_param(snd_pcm_hw_params_t *params, unsigned int k)
821 {
822 printf("%s: ", snd_pcm_hw_param_name(k));
823 snd_pcm_hw_param_dump(params, k);
824 printf("\n");
825 }
826
snd_pcm_hw_params_dump(snd_pcm_hw_params_t * params)827 int snd_pcm_hw_params_dump(snd_pcm_hw_params_t *params)
828 {
829 unsigned int k;
830 for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++)
831 dump_one_param(params, k);
832 return 0;
833 }
834
snd_pcm_format_size(snd_pcm_format_t format,size_t samples)835 ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
836 {
837 int size = 0;
838 size = snd_pcm_format_physical_width(format);
839 if (size < 0)
840 return size;
841 return (size * samples / 8);
842 }
843
snd_pcm_bytes_to_frames(snd_pcm_t * pcm,ssize_t bytes)844 snd_pcm_sframes_t snd_pcm_bytes_to_frames(snd_pcm_t *pcm, ssize_t bytes)
845 {
846 assert(pcm);
847 return bytes * 8 / pcm->frame_bits;
848 }
849
snd_pcm_frames_to_bytes(snd_pcm_t * pcm,snd_pcm_sframes_t frames)850 ssize_t snd_pcm_frames_to_bytes(snd_pcm_t *pcm, snd_pcm_sframes_t frames)
851 {
852 assert(pcm);
853 return frames * pcm->frame_bits / 8;
854 }
855
snd_pcm_hw_params_can_pause(const snd_pcm_hw_params_t * params)856 int snd_pcm_hw_params_can_pause(const snd_pcm_hw_params_t *params)
857 {
858 assert(params);
859
860 return !!params->can_paused;
861 }
862
863
864 #define PCMTYPE(v) [SND_PCM_TYPE_##v] = #v
865 #define STATE(v) [SND_PCM_STATE_##v] = #v
866 #define STREAM(v) [SND_PCM_STREAM_##v] = #v
867 #define ACCESS(v) [SND_PCM_ACCESS_##v] = #v
868 #define FORMAT(v) [SND_PCM_FORMAT_##v] = #v
869
870 static const char *const snd_pcm_stream_names[] = {
871 STREAM(PLAYBACK),
872 STREAM(CAPTURE),
873 };
874
875 static const char *const snd_pcm_state_names[] = {
876 STATE(OPEN),
877 STATE(SETUP),
878 STATE(PREPARED),
879 STATE(RUNNING),
880 STATE(XRUN),
881 STATE(DRAINING),
882 STATE(PAUSED),
883 STATE(SUSPENDED),
884 STATE(DISCONNECTED),
885 };
886
887 static const char *const snd_pcm_access_names[] = {
888 ACCESS(MMAP_INTERLEAVED),
889 ACCESS(MMAP_NONINTERLEAVED),
890 ACCESS(MMAP_COMPLEX),
891 ACCESS(RW_INTERLEAVED),
892 ACCESS(RW_NONINTERLEAVED),
893 };
894
895 static const char *const snd_pcm_format_names[] = {
896 FORMAT(S8),
897 FORMAT(U8),
898 FORMAT(S16_LE),
899 FORMAT(S16_BE),
900 FORMAT(U16_LE),
901 FORMAT(U16_BE),
902 FORMAT(S24_LE),
903 FORMAT(S24_BE),
904 FORMAT(U24_LE),
905 FORMAT(U24_BE),
906 FORMAT(S32_LE),
907 FORMAT(S32_BE),
908 FORMAT(U32_LE),
909 FORMAT(U32_BE),
910 };
911
912 static const char *const snd_pcm_type_names[] = {
913 PCMTYPE(HW),
914 PCMTYPE(MULTI),
915 PCMTYPE(LINEAR),
916 PCMTYPE(FILE),
917 PCMTYPE(RATE),
918 PCMTYPE(ROUTE),
919 PCMTYPE(PLUG),
920 PCMTYPE(DMIX),
921 PCMTYPE(DSNOOP),
922 PCMTYPE(SOFTVOL),
923 PCMTYPE(EXTPLUG),
924 };
925
snd_pcm_stream_name(snd_pcm_stream_t stream)926 const char *snd_pcm_stream_name(snd_pcm_stream_t stream)
927 {
928 if (stream > SND_PCM_STREAM_LAST)
929 return NULL;
930 return snd_pcm_stream_names[stream];
931 }
932
snd_pcm_access_name(snd_pcm_access_t acc)933 const char *snd_pcm_access_name(snd_pcm_access_t acc)
934 {
935 if (acc > SND_PCM_ACCESS_LAST)
936 return NULL;
937 return snd_pcm_access_names[acc];
938 }
939
snd_pcm_format_name(snd_pcm_format_t format)940 const char *snd_pcm_format_name(snd_pcm_format_t format)
941 {
942 if (format > SND_PCM_FORMAT_LAST)
943 return NULL;
944 return snd_pcm_format_names[format];
945 }
946
snd_pcm_state_name(snd_pcm_state_t state)947 const char *snd_pcm_state_name(snd_pcm_state_t state)
948 {
949 if (state > SND_PCM_STATE_LAST)
950 return NULL;
951 return snd_pcm_state_names[state];
952 }
953
snd_pcm_type_name(snd_pcm_type_t type)954 const char *snd_pcm_type_name(snd_pcm_type_t type)
955 {
956 if (type > SND_PCM_TYPE_LAST)
957 return NULL;
958 return snd_pcm_type_names[type];
959 }
960
snd_pcm_new(snd_pcm_t ** pcmp,snd_pcm_type_t type,const char * name,snd_pcm_stream_t stream,int mode)961 int snd_pcm_new(snd_pcm_t **pcmp, snd_pcm_type_t type, const char *name, snd_pcm_stream_t stream, int mode)
962 {
963 snd_pcm_t *pcm;
964
965 pcm = snd_malloc(sizeof(snd_pcm_t));
966 if (!pcm)
967 return -ENOMEM;
968 pcm->type = type;
969 if (name)
970 pcm->name = strdup(name);
971 pcm->stream = stream;
972 pcm->mode = mode;
973 pcm->op_arg = pcm;
974 pcm->fast_op_arg = pcm;
975
976 pthread_mutex_init(&pcm->lock, NULL);
977
978 *pcmp = pcm;
979 return 0;
980 }
981
snd_pcm_free(snd_pcm_t * pcm)982 int snd_pcm_free(snd_pcm_t *pcm)
983 {
984 assert(pcm);
985 if (pcm->name)
986 free(pcm->name);
987 if (pcm->hw.link_dst)
988 free(pcm->hw.link_dst);
989 if (pcm->appl.link_dst)
990 free(pcm->appl.link_dst);
991 pthread_mutex_destroy(&pcm->lock);
992 snd_free(pcm);
993 return 0;
994 }
995
snd_pcm_areas_from_buf(snd_pcm_t * pcm,snd_pcm_channel_area_t * areas,void * buf)996 void snd_pcm_areas_from_buf(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void *buf)
997 {
998 unsigned int channel;
999 unsigned int channels;
1000
1001 snd_pcm_lock(pcm);
1002 channels = pcm->channels;
1003 for (channel = 0; channel < channels; ++channel, ++areas) {
1004 areas->addr = buf;
1005 areas->first = channel * pcm->sample_bits;
1006 areas->step = pcm->frame_bits;
1007 }
1008 snd_pcm_unlock(pcm);
1009 }
1010
snd_pcm_areas_from_bufs(snd_pcm_t * pcm,snd_pcm_channel_area_t * areas,void ** bufs)1011 void snd_pcm_areas_from_bufs(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void **bufs)
1012 {
1013 unsigned int channel;
1014 unsigned int channels;
1015
1016 snd_pcm_lock(pcm);
1017 channels = pcm->channels;
1018 for (channel = 0; channel < channels; ++channel, ++areas, ++bufs) {
1019 areas->addr = *bufs;
1020 areas->first = 0;
1021 areas->step = pcm->sample_bits;
1022 }
1023 snd_pcm_unlock(pcm);
1024 }
1025
snd_pcm_read_areas(snd_pcm_t * pcm,const snd_pcm_channel_area_t * areas,snd_pcm_uframes_t offset,snd_pcm_uframes_t size,snd_pcm_xfer_areas_func_t func)1026 snd_pcm_sframes_t snd_pcm_read_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_t *areas,
1027 snd_pcm_uframes_t offset, snd_pcm_uframes_t size,
1028 snd_pcm_xfer_areas_func_t func)
1029 {
1030 snd_pcm_uframes_t xfer = 0;
1031 snd_pcm_sframes_t err = 0;
1032 snd_pcm_state_t state;
1033
1034 if (size == 0)
1035 return 0;
1036
1037 snd_pcm_lock(pcm); /* forced lock */
1038 while (size > 0) {
1039 snd_pcm_uframes_t frames;
1040 snd_pcm_sframes_t avail;
1041 _again:
1042 state = __snd_pcm_state(pcm);
1043 switch (state) {
1044 case SND_PCM_STATE_PREPARED:
1045 err = __snd_pcm_start(pcm);
1046 if (err < 0)
1047 goto _end;
1048 break;
1049 case SND_PCM_STATE_RUNNING:
1050 err = __snd_pcm_hwsync(pcm);
1051 if (err < 0)
1052 goto _end;
1053 break;
1054 case SND_PCM_STATE_DRAINING:
1055 case SND_PCM_STATE_PAUSED:
1056 break;
1057 case SND_PCM_STATE_XRUN:
1058 err = -EPIPE;
1059 goto _end;
1060 case SND_PCM_STATE_SUSPENDED:
1061 err = -ESTRPIPE;
1062 goto _end;
1063 case SND_PCM_STATE_DISCONNECTED:
1064 err = -ENODEV;
1065 goto _end;
1066 default:
1067 err = -EBADFD;
1068 goto _end;
1069 }
1070 avail = __snd_pcm_avail_update(pcm);
1071 if (avail < 0) {
1072 err = avail;
1073 goto _end;
1074 }
1075 if (avail == 0) {
1076 if (state == SND_PCM_STATE_DRAINING)
1077 goto _end;
1078 #if 0
1079 if (pcm->mode & SND_PCM_NONBLOCK) {
1080 err = -EAGAIN;
1081 goto _end;
1082 }
1083 #endif
1084 err = __snd_pcm_wait_in_lock(pcm, -1);
1085 if (err < 0)
1086 break;
1087 goto _again;
1088 }
1089 frames = size;
1090 if (frames > (snd_pcm_uframes_t) avail)
1091 frames = avail;
1092 if (! frames)
1093 break;
1094 err = func(pcm, areas, offset, frames);
1095 if (err < 0)
1096 break;
1097 frames = err;
1098 offset += frames;
1099 size -= frames;
1100 xfer += frames;
1101 }
1102 _end:
1103 snd_pcm_unlock(pcm);
1104 return xfer > 0 ? (snd_pcm_sframes_t) xfer : snd_pcm_check_error(pcm, err);
1105 }
1106
snd_pcm_write_areas(snd_pcm_t * pcm,const snd_pcm_channel_area_t * areas,snd_pcm_uframes_t offset,snd_pcm_uframes_t size,snd_pcm_xfer_areas_func_t func)1107 snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_t *areas,
1108 snd_pcm_uframes_t offset, snd_pcm_uframes_t size,
1109 snd_pcm_xfer_areas_func_t func)
1110 {
1111 snd_pcm_uframes_t xfer = 0;
1112 snd_pcm_sframes_t err = 0;
1113 snd_pcm_state_t state;
1114
1115 if (size == 0)
1116 return 0;
1117
1118 awalsa_debug("\n");
1119 snd_pcm_lock(pcm); /* forced lock */
1120 while (size > 0) {
1121 snd_pcm_uframes_t frames;
1122 snd_pcm_sframes_t avail;
1123 _again:
1124 state = __snd_pcm_state(pcm);
1125 switch (state) {
1126 case SND_PCM_STATE_PREPARED:
1127 case SND_PCM_STATE_PAUSED:
1128 break;
1129 case SND_PCM_STATE_RUNNING:
1130 err = __snd_pcm_hwsync(pcm);
1131 if (err < 0)
1132 goto _end;
1133 break;
1134 case SND_PCM_STATE_XRUN:
1135 err = -EPIPE;
1136 goto _end;
1137 case SND_PCM_STATE_SUSPENDED:
1138 err = -ESTRPIPE;
1139 goto _end;
1140 case SND_PCM_STATE_DISCONNECTED:
1141 err = -ENODEV;
1142 goto _end;
1143 default:
1144 err = -EBADFD;
1145 goto _end;
1146 }
1147 avail = __snd_pcm_avail_update(pcm);
1148 awalsa_debug("size:%ld, avail: %ld, pcm_type=%s, state=%d\n",
1149 size, avail, snd_pcm_type_name(snd_pcm_type(pcm)), state);
1150 if (avail < 0) {
1151 err = avail;
1152 goto _end;
1153 }
1154
1155 /* wait to get avail_min */
1156 #if 1
1157 if ((state == SND_PCM_STATE_RUNNING &&
1158 size > (snd_pcm_uframes_t)avail &&
1159 snd_pcm_may_wait_for_avail_min(pcm, avail))) {
1160 err = snd_pcm_wait_nocheck(pcm, -1);
1161 if (err < 0)
1162 break;
1163 goto _again;
1164 }
1165 #endif
1166
1167 frames = size;
1168 if (frames > (snd_pcm_uframes_t) avail)
1169 frames = avail;
1170 if (! frames) {
1171 awalsa_info("avail=%ld, size=%ld, start=%ld, stop=%ld, xfer=%lu\n",
1172 avail, size, pcm->start_threshold, pcm->stop_threshold, xfer);
1173 #if 0
1174 break;
1175 #else
1176 /* avail is 0 in some case, don't break and return,
1177 * Now msleep and continue, in order to wait dma consume data,
1178 * and then avail is larger than 0.
1179 * */
1180 usleep(3000);
1181 continue;
1182 #endif
1183 }
1184 err = func(pcm, areas, offset, frames);
1185 if (err < 0)
1186 break;
1187 frames = err;
1188 if (state == SND_PCM_STATE_PREPARED) {
1189 snd_pcm_sframes_t hw_avail = pcm->buffer_size - avail;
1190 hw_avail += frames;
1191 /* some plugins might automatically start the stream */
1192 awalsa_debug("hw_avail=%d, start_threshold=%d\n",
1193 hw_avail, pcm->start_threshold);
1194 state = __snd_pcm_state(pcm);
1195 if (state == SND_PCM_STATE_PREPARED &&
1196 hw_avail >= (snd_pcm_sframes_t) pcm->start_threshold) {
1197 err = __snd_pcm_start(pcm);
1198 if (err < 0)
1199 goto _end;
1200 }
1201 }
1202 offset += frames;
1203 size -= frames;
1204 xfer += frames;
1205 }
1206 _end:
1207 snd_pcm_unlock(pcm);
1208 return xfer > 0 ? (snd_pcm_sframes_t) xfer : snd_pcm_check_error(pcm, err);
1209 }
1210
snd_pcm_format_silence_64(snd_pcm_format_t format)1211 u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format)
1212 {
1213 switch (format) {
1214 case SND_PCM_FORMAT_S8:
1215 case SND_PCM_FORMAT_S16_LE:
1216 case SND_PCM_FORMAT_S16_BE:
1217 case SND_PCM_FORMAT_S24_LE:
1218 case SND_PCM_FORMAT_S24_BE:
1219 case SND_PCM_FORMAT_S32_LE:
1220 case SND_PCM_FORMAT_S32_BE:
1221 return 0;
1222 case SND_PCM_FORMAT_U8:
1223 return 0x8080808080808080ULL;
1224 case SND_PCM_FORMAT_U16_LE:
1225 return 0x8000800080008000ULL;
1226 case SND_PCM_FORMAT_U24_LE:
1227 return 0x0080000000800000ULL;
1228 case SND_PCM_FORMAT_U32_LE:
1229 return 0x8000000080000000ULL;
1230 case SND_PCM_FORMAT_U16_BE:
1231 return 0x0080008000800080ULL;
1232 case SND_PCM_FORMAT_U24_BE:
1233 return 0x0000800000008000ULL;
1234 case SND_PCM_FORMAT_U32_BE:
1235 return 0x0000008000000080ULL;
1236 default:
1237 assert(0);
1238 return 0;
1239 }
1240 return 0;
1241 }
1242
snd_pcm_area_silence(const snd_pcm_channel_area_t * dst_area,snd_pcm_uframes_t dst_offset,unsigned int samples,snd_pcm_format_t format)1243 int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes_t dst_offset,
1244 unsigned int samples, snd_pcm_format_t format)
1245 {
1246 /* FIXME: sub byte resolution and odd dst_offset */
1247 char *dst;
1248 unsigned int dst_step;
1249 int width;
1250 u_int64_t silence;
1251 if (!dst_area->addr)
1252 return 0;
1253 dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
1254 width = snd_pcm_format_physical_width(format);
1255 silence = snd_pcm_format_silence_64(format);
1256 #if 0
1257 /* dst may not be 8bytes align, so can't clear with strdne (64bit operation) */
1258 if (dst_area->step == (unsigned int) width) {
1259 unsigned int dwords = samples * width / 64;
1260 u_int64_t *dstp = (u_int64_t *)dst;
1261 samples -= dwords * 64 / width;
1262 while (dwords-- > 0)
1263 *dstp++ = silence;
1264 if (samples == 0)
1265 return 0;
1266 dst = (char *)dstp;
1267 }
1268 #endif
1269 dst_step = dst_area->step / 8;
1270 switch (width) {
1271 case 4: {
1272 u_int8_t s0 = silence & 0xf0;
1273 u_int8_t s1 = silence & 0x0f;
1274 int dstbit = dst_area->first % 8;
1275 int dstbit_step = dst_area->step % 8;
1276 while (samples-- > 0) {
1277 if (dstbit) {
1278 *dst &= 0xf0;
1279 *dst |= s1;
1280 } else {
1281 *dst &= 0x0f;
1282 *dst |= s0;
1283 }
1284 dst += dst_step;
1285 dstbit += dstbit_step;
1286 if (dstbit == 8) {
1287 dst++;
1288 dstbit = 0;
1289 }
1290 }
1291 break;
1292 }
1293 case 8: {
1294 u_int8_t sil = silence;
1295 while (samples-- > 0) {
1296 *dst = sil;
1297 dst += dst_step;
1298 }
1299 break;
1300 }
1301 case 16: {
1302 u_int16_t sil = silence;
1303 while (samples-- > 0) {
1304 *(u_int16_t*)dst = sil;
1305 dst += dst_step;
1306 }
1307 break;
1308 }
1309 case 24:
1310 *(dst + 0) = silence >> 0;
1311 *(dst + 1) = silence >> 8;
1312 *(dst + 2) = silence >> 16;
1313 break;
1314 case 32: {
1315 u_int32_t sil = silence;
1316 while (samples-- > 0) {
1317 *(u_int32_t*)dst = sil;
1318 dst += dst_step;
1319 }
1320 break;
1321 }
1322 case 64: {
1323 while (samples-- > 0) {
1324 *(u_int64_t*)dst = silence;
1325 dst += dst_step;
1326 }
1327 break;
1328 }
1329 default:
1330 awalsa_err("invalid format width %d", width);
1331 return -EINVAL;
1332 }
1333 return 0;
1334 }
1335
snd_pcm_areas_silence(const snd_pcm_channel_area_t * dst_areas,snd_pcm_uframes_t dst_offset,unsigned int channels,snd_pcm_uframes_t frames,snd_pcm_format_t format)1336 int snd_pcm_areas_silence(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset,
1337 unsigned int channels, snd_pcm_uframes_t frames, snd_pcm_format_t format)
1338 {
1339 int width = snd_pcm_format_physical_width(format);
1340 while (channels > 0) {
1341 void *addr = dst_areas->addr;
1342 unsigned int step = dst_areas->step;
1343 const snd_pcm_channel_area_t *begin = dst_areas;
1344 int channels1 = channels;
1345 unsigned int chns = 0;
1346 int err;
1347 while (1) {
1348 channels1--;
1349 chns++;
1350 dst_areas++;
1351 if (channels1 == 0 ||
1352 dst_areas->addr != addr ||
1353 dst_areas->step != step ||
1354 dst_areas->first != dst_areas[-1].first + width)
1355 break;
1356 }
1357 if (chns > 1 && chns * width == step) {
1358 /* Collapse the areas */
1359 snd_pcm_channel_area_t d;
1360 d.addr = begin->addr;
1361 d.first = begin->first;
1362 d.step = width;
1363 err = snd_pcm_area_silence(&d, dst_offset * chns, frames * chns, format);
1364 channels -= chns;
1365 } else {
1366 err = snd_pcm_area_silence(begin, dst_offset, frames, format);
1367 dst_areas = begin + 1;
1368 channels--;
1369 }
1370 if (err < 0)
1371 return err;
1372 }
1373 return 0;
1374 }
1375
snd_pcm_area_copy(const snd_pcm_channel_area_t * dst_area,snd_pcm_uframes_t dst_offset,const snd_pcm_channel_area_t * src_area,snd_pcm_uframes_t src_offset,unsigned int samples,snd_pcm_format_t format)1376 int snd_pcm_area_copy(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes_t dst_offset,
1377 const snd_pcm_channel_area_t *src_area, snd_pcm_uframes_t src_offset,
1378 unsigned int samples, snd_pcm_format_t format)
1379 {
1380 /* FIXME: sub byte resolution and odd dst_offset */
1381 const char *src;
1382 char *dst;
1383 int width;
1384 int src_step, dst_step;
1385 if (dst_area == src_area && dst_offset == src_offset)
1386 return 0;
1387 if (!src_area->addr)
1388 return snd_pcm_area_silence(dst_area, dst_offset, samples, format);
1389 src = snd_pcm_channel_area_addr(src_area, src_offset);
1390 if (!dst_area->addr)
1391 return 0;
1392 dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
1393 width = snd_pcm_format_physical_width(format);
1394 if (src_area->step == (unsigned int) width &&
1395 dst_area->step == (unsigned int) width) {
1396 size_t bytes = samples * width / 8;
1397 samples -= bytes * 8 / width;
1398 assert(src < dst || src >= dst + bytes);
1399 assert(dst < src || dst >= src + bytes);
1400 memcpy(dst, src, bytes);
1401 if (samples == 0)
1402 return 0;
1403 }
1404 src_step = src_area->step / 8;
1405 dst_step = dst_area->step / 8;
1406 switch (width) {
1407 case 4: {
1408 int srcbit = src_area->first % 8;
1409 int srcbit_step = src_area->step % 8;
1410 int dstbit = dst_area->first % 8;
1411 int dstbit_step = dst_area->step % 8;
1412 while (samples-- > 0) {
1413 unsigned char srcval;
1414 if (srcbit)
1415 srcval = *src & 0x0f;
1416 else
1417 srcval = *src & 0xf0;
1418 if (dstbit)
1419 *dst &= 0xf0;
1420 else
1421 *dst &= 0x0f;
1422 *dst |= srcval;
1423 src += src_step;
1424 srcbit += srcbit_step;
1425 if (srcbit == 8) {
1426 src++;
1427 srcbit = 0;
1428 }
1429 dst += dst_step;
1430 dstbit += dstbit_step;
1431 if (dstbit == 8) {
1432 dst++;
1433 dstbit = 0;
1434 }
1435 }
1436 break;
1437 }
1438 case 8: {
1439 while (samples-- > 0) {
1440 *dst = *src;
1441 src += src_step;
1442 dst += dst_step;
1443 }
1444 break;
1445 }
1446 case 16: {
1447 while (samples-- > 0) {
1448 *(u_int16_t*)dst = *(const u_int16_t*)src;
1449 src += src_step;
1450 dst += dst_step;
1451 }
1452 break;
1453 }
1454 case 24:
1455 while (samples-- > 0) {
1456 *(dst + 0) = *(src + 0);
1457 *(dst + 1) = *(src + 1);
1458 *(dst + 2) = *(src + 2);
1459 src += src_step;
1460 dst += dst_step;
1461 }
1462 break;
1463 case 32: {
1464 while (samples-- > 0) {
1465 *(u_int32_t*)dst = *(const u_int32_t*)src;
1466 src += src_step;
1467 dst += dst_step;
1468 }
1469 break;
1470 }
1471 case 64: {
1472 while (samples-- > 0) {
1473 *(u_int64_t*)dst = *(const u_int64_t*)src;
1474 src += src_step;
1475 dst += dst_step;
1476 }
1477 break;
1478 }
1479 default:
1480 awalsa_err("invalid format width %d", width);
1481 return -EINVAL;
1482 }
1483 return 0;
1484 }
1485
snd_pcm_areas_copy(const snd_pcm_channel_area_t * dst_areas,snd_pcm_uframes_t dst_offset,const snd_pcm_channel_area_t * src_areas,snd_pcm_uframes_t src_offset,unsigned int channels,snd_pcm_uframes_t frames,snd_pcm_format_t format)1486 int snd_pcm_areas_copy(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset,
1487 const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset,
1488 unsigned int channels, snd_pcm_uframes_t frames, snd_pcm_format_t format)
1489 {
1490 int width = snd_pcm_format_physical_width(format);
1491 assert(dst_areas);
1492 assert(src_areas);
1493 if (! channels) {
1494 awalsa_err("invalid channels %d\n", channels);
1495 return -EINVAL;
1496 }
1497 if (! frames) {
1498 awalsa_err("invalid frames %ld\n", frames);
1499 return -EINVAL;
1500 }
1501 while (channels > 0) {
1502 unsigned int step = src_areas->step;
1503 void *src_addr = src_areas->addr;
1504 const snd_pcm_channel_area_t *src_start = src_areas;
1505 void *dst_addr = dst_areas->addr;
1506 const snd_pcm_channel_area_t *dst_start = dst_areas;
1507 int channels1 = channels;
1508 unsigned int chns = 0;
1509 while (dst_areas->step == step) {
1510 channels1--;
1511 chns++;
1512 src_areas++;
1513 dst_areas++;
1514 if (channels1 == 0 ||
1515 src_areas->step != step ||
1516 src_areas->addr != src_addr ||
1517 dst_areas->addr != dst_addr ||
1518 src_areas->first != src_areas[-1].first + width ||
1519 dst_areas->first != dst_areas[-1].first + width)
1520 break;
1521 }
1522 if (chns > 1 && chns * width == step) {
1523 if (src_offset != dst_offset ||
1524 src_start->addr != dst_start->addr ||
1525 src_start->first != dst_start->first) {
1526 /* Collapse the areas */
1527 snd_pcm_channel_area_t s, d;
1528 s.addr = src_start->addr;
1529 s.first = src_start->first;
1530 s.step = width;
1531 d.addr = dst_start->addr;
1532 d.first = dst_start->first;
1533 d.step = width;
1534 snd_pcm_area_copy(&d, dst_offset * chns,
1535 &s, src_offset * chns,
1536 frames * chns, format);
1537 }
1538 channels -= chns;
1539 } else {
1540 snd_pcm_area_copy(dst_start, dst_offset,
1541 src_start, src_offset,
1542 frames, format);
1543 src_areas = src_start + 1;
1544 dst_areas = dst_start + 1;
1545 channels--;
1546 }
1547 }
1548 return 0;
1549 }
1550
1551 /* This function is called inside pcm lock. */
snd_pcm_wait_nocheck(snd_pcm_t * pcm,int timeout)1552 int snd_pcm_wait_nocheck(snd_pcm_t *pcm, int timeout)
1553 {
1554 assert(pcm);
1555 if (pcm->fast_ops->wait)
1556 return pcm->fast_ops->wait(pcm->fast_op_arg, timeout);
1557 else
1558 awalsa_err("pcm_type=%s, no wait\n", snd_pcm_type_name(snd_pcm_type(pcm)));
1559 return 0;
1560 }
1561
__snd_pcm_wait_in_lock(snd_pcm_t * pcm,int timeout)1562 int __snd_pcm_wait_in_lock(snd_pcm_t *pcm, int timeout)
1563 {
1564 #if 1
1565 awalsa_debug("\n");
1566 if (!snd_pcm_may_wait_for_avail_min(pcm, snd_pcm_mmap_avail(pcm))) {
1567 /* check more precisely */
1568 switch (__snd_pcm_state(pcm)) {
1569 case SND_PCM_STATE_XRUN:
1570 return -EPIPE;
1571 case SND_PCM_STATE_SUSPENDED:
1572 return -ESTRPIPE;
1573 case SND_PCM_STATE_DISCONNECTED:
1574 return -ENODEV;
1575 default:
1576 return 1;
1577 }
1578 }
1579 return snd_pcm_wait_nocheck(pcm, timeout);
1580 #else
1581 switch (__snd_pcm_state(pcm)) {
1582 case SND_PCM_STATE_XRUN:
1583 return -EPIPE;
1584 case SND_PCM_STATE_SUSPENDED:
1585 return -ESTRPIPE;
1586 case SND_PCM_STATE_DISCONNECTED:
1587 return -ENODEV;
1588 default:
1589 return 1;
1590 }
1591 #endif
1592 }
1593
snd_pcm_wait(snd_pcm_t * pcm,int timeout)1594 int snd_pcm_wait(snd_pcm_t *pcm, int timeout)
1595 {
1596 int err;
1597 awalsa_debug("\n");
1598
1599 snd_pcm_lock(pcm); /* forced lock */
1600 err = __snd_pcm_wait_in_lock(pcm, timeout);
1601 snd_pcm_unlock(pcm);
1602 return err;
1603 }
1604
snd_pcm_avail_update(snd_pcm_t * pcm)1605 snd_pcm_sframes_t snd_pcm_avail_update(snd_pcm_t *pcm)
1606 {
1607 snd_pcm_sframes_t result;
1608 awalsa_debug("\n");
1609
1610 snd_pcm_lock(pcm);
1611 result = __snd_pcm_avail_update(pcm);
1612 snd_pcm_unlock(pcm);
1613 return result;
1614 }
1615
__snd_pcm_mmap_begin(snd_pcm_t * pcm,const snd_pcm_channel_area_t ** areas,snd_pcm_uframes_t * offset,snd_pcm_uframes_t * frames)1616 int __snd_pcm_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas,
1617 snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames)
1618 {
1619 snd_pcm_uframes_t cont;
1620 snd_pcm_uframes_t f;
1621 snd_pcm_uframes_t avail;
1622 const snd_pcm_channel_area_t *xareas;
1623 assert(pcm && areas && offset && frames);
1624
1625 awalsa_debug("\n");
1626
1627 xareas = snd_pcm_mmap_areas(pcm);
1628 if (xareas == NULL)
1629 return -EBADFD;
1630 *areas = xareas;
1631 *offset = *pcm->appl.ptr % pcm->buffer_size;
1632 avail = snd_pcm_mmap_avail(pcm);
1633 if (avail > pcm->buffer_size)
1634 avail = pcm->buffer_size;
1635 cont = pcm->buffer_size - *offset;
1636 f = *frames;
1637 if (f > avail)
1638 f = avail;
1639 if (f > cont)
1640 f = cont;
1641 *frames = f;
1642 return 0;
1643 }
1644
snd_pcm_mmap_begin(snd_pcm_t * pcm,const snd_pcm_channel_area_t ** areas,snd_pcm_uframes_t * offset,snd_pcm_uframes_t * frames)1645 int snd_pcm_mmap_begin(snd_pcm_t *pcm,
1646 const snd_pcm_channel_area_t **areas,
1647 snd_pcm_uframes_t *offset,
1648 snd_pcm_uframes_t *frames)
1649 {
1650 int err;
1651 awalsa_debug("\n");
1652
1653 snd_pcm_lock(pcm);
1654 err = __snd_pcm_mmap_begin(pcm, areas, offset, frames);
1655 snd_pcm_unlock(pcm);
1656 return err;
1657 }
1658
__snd_pcm_mmap_commit(snd_pcm_t * pcm,snd_pcm_uframes_t offset,snd_pcm_uframes_t frames)1659 snd_pcm_sframes_t __snd_pcm_mmap_commit(snd_pcm_t *pcm,
1660 snd_pcm_uframes_t offset,
1661 snd_pcm_uframes_t frames)
1662 {
1663 assert(pcm);
1664 awalsa_debug("\n");
1665
1666 if (offset != *pcm->appl.ptr % pcm->buffer_size) {
1667 awalsa_err("commit offset (%ld) doesn't match with appl_ptr (%ld) %% buf_size (%ld)\n",
1668 offset, *pcm->appl.ptr, pcm->buffer_size);
1669 return -EPIPE;
1670 }
1671 if (frames > snd_pcm_mmap_avail(pcm)) {
1672 awalsa_err("commit frames (%ld) overflow (avail = %ld)\n", frames,
1673 snd_pcm_mmap_avail(pcm));
1674 return -EPIPE;
1675 }
1676 return pcm->fast_ops->mmap_commit(pcm->fast_op_arg, offset, frames);
1677 }
1678
snd_pcm_mmap_commit(snd_pcm_t * pcm,snd_pcm_uframes_t offset,snd_pcm_uframes_t frames)1679 snd_pcm_sframes_t snd_pcm_mmap_commit(snd_pcm_t *pcm,
1680 snd_pcm_uframes_t offset,
1681 snd_pcm_uframes_t frames)
1682 {
1683 snd_pcm_sframes_t result;
1684 awalsa_debug("\n");
1685
1686 snd_pcm_lock(pcm);
1687 result = __snd_pcm_mmap_commit(pcm, offset, frames);
1688 snd_pcm_unlock(pcm);
1689 return result;
1690 }
1691
snd_pcm_type(snd_pcm_t * pcm)1692 snd_pcm_type_t snd_pcm_type(snd_pcm_t *pcm)
1693 {
1694 assert(pcm);
1695 return pcm->type;
1696 }
1697
1698
chmap_equal(const snd_pcm_chmap_t * a,const snd_pcm_chmap_t * b)1699 static int chmap_equal(const snd_pcm_chmap_t *a, const snd_pcm_chmap_t *b)
1700 {
1701 if (a->channels != b->channels)
1702 return 0;
1703 return !memcmp(a->pos, b->pos, a->channels * sizeof(a->pos[0]));
1704 }
1705
1706 /**
1707 * \!brief Query the available channel maps
1708 * \param pcm PCM handle to query
1709 * \return the NULL-terminated array of integer pointers, each of
1710 * which contains the channel map. A channel map is represented by an
1711 * integer array, beginning with the channel map type, followed by the
1712 * number of channels, and the position of each channel.
1713 *
1714 * Note: the caller is requested to release the returned value via
1715 * snd_pcm_free_chmaps().
1716 */
snd_pcm_query_chmaps(snd_pcm_t * pcm)1717 snd_pcm_chmap_query_t **snd_pcm_query_chmaps(snd_pcm_t *pcm)
1718 {
1719 if (!pcm->ops->query_chmaps)
1720 return NULL;
1721 return pcm->ops->query_chmaps(pcm);
1722 }
1723
1724 /**
1725 * \!brief Release the channel map array allocated via #snd_pcm_query_chmaps
1726 * \param maps the array pointer to release
1727 */
snd_pcm_free_chmaps(snd_pcm_chmap_query_t ** maps)1728 void snd_pcm_free_chmaps(snd_pcm_chmap_query_t **maps)
1729 {
1730 snd_pcm_chmap_query_t **p;
1731 if (!maps)
1732 return;
1733 for (p = maps; *p; p++)
1734 free(*p);
1735 free(maps);
1736 }
1737
1738 /**
1739 * \!brief Get the current channel map
1740 * \param pcm PCM instance
1741 * \return the current channel map, or NULL if error
1742 *
1743 * Note: the caller is requested to release the returned value via free()
1744 */
snd_pcm_get_chmap(snd_pcm_t * pcm)1745 snd_pcm_chmap_t *snd_pcm_get_chmap(snd_pcm_t *pcm)
1746 {
1747 if (!pcm->ops->get_chmap)
1748 return NULL;
1749 return pcm->ops->get_chmap(pcm);
1750 }
1751
1752 /**
1753 * \!brief Configure the current channel map
1754 * \param pcm PCM instance
1755 * \param map the channel map to write
1756 * \return zero if succeeded, or a negative error code
1757 */
snd_pcm_set_chmap(snd_pcm_t * pcm,const snd_pcm_chmap_t * map)1758 int snd_pcm_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
1759 {
1760 const snd_pcm_chmap_t *oldmap = snd_pcm_get_chmap(pcm);
1761 if (oldmap && chmap_equal(oldmap, map))
1762 return 0;
1763
1764 if (!pcm->ops->set_chmap)
1765 return -ENXIO;
1766 return pcm->ops->set_chmap(pcm, map);
1767 }
1768
1769 /* copy a single channel map with the fixed type to chmap_query pointer */
_copy_to_fixed_query_map(snd_pcm_chmap_query_t ** dst,const snd_pcm_chmap_t * src)1770 static int _copy_to_fixed_query_map(snd_pcm_chmap_query_t **dst,
1771 const snd_pcm_chmap_t *src)
1772 {
1773 *dst = malloc((src->channels + 2) * sizeof(int));
1774 if (!*dst)
1775 return -ENOMEM;
1776 (*dst)->type = SND_CHMAP_TYPE_FIXED;
1777 memcpy(&(*dst)->map, src, (src->channels + 1) * sizeof(int));
1778 return 0;
1779 }
1780
1781 /* make a chmap_query array from a single channel map */
_snd_pcm_make_single_query_chmaps(const snd_pcm_chmap_t * src)1782 snd_pcm_chmap_query_t **_snd_pcm_make_single_query_chmaps(const snd_pcm_chmap_t *src)
1783 {
1784 snd_pcm_chmap_query_t **maps;
1785
1786 maps = calloc(2, sizeof(*maps));
1787 if (!maps)
1788 return NULL;
1789 if (_copy_to_fixed_query_map(maps, src)) {
1790 free(maps);
1791 return NULL;
1792 }
1793 return maps;
1794 }
1795
snd_pcm_rewind(snd_pcm_t * pcm,snd_pcm_uframes_t frames)1796 snd_pcm_sframes_t snd_pcm_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
1797 {
1798 snd_pcm_sframes_t result = 0;
1799
1800 assert(pcm);
1801 if (! pcm->setup) {
1802 awalsa_err("PCM not set up");
1803 return -EIO;
1804 }
1805 if (frames == 0)
1806 return 0;
1807 //if (bad_pcm_state(pcm, P_STATE_RUNNABLE))
1808 // return -EBADFD;
1809 snd_pcm_lock(pcm);
1810 #if 0
1811 result = pcm->fast_ops->rewind(pcm->fast_op_arg, frames);
1812 #else
1813 awalsa_err("rewind is not supported\n");
1814 #endif
1815 snd_pcm_unlock(pcm);
1816 return result;
1817 }
1818
snd_pcm_link(snd_pcm_t * pcm1,snd_pcm_t * pcm2)1819 int snd_pcm_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
1820 {
1821 assert(pcm1);
1822 assert(pcm2);
1823 if (pcm1->fast_ops->link)
1824 return pcm1->fast_ops->link(pcm1, pcm2);
1825 return -ENOSYS;
1826 }
1827
snd_pcm_unlink(snd_pcm_t * pcm)1828 int snd_pcm_unlink(snd_pcm_t *pcm)
1829 {
1830 assert(pcm);
1831 if (pcm->fast_ops->unlink)
1832 return pcm->fast_ops->unlink(pcm);
1833 return -ENOSYS;
1834 }
1835
1836 #ifdef AW_ALSA_LIB_API_TEST
1837 #include "test/tt-aw-alsa-lib.c"
1838 #endif
1839