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