1 /**
2 * \file pcm/pcm_alaw.c
3 * \ingroup PCM_Plugins
4 * \brief PCM A-Law Conversion Plugin Interface
5 * \author Abramo Bagnara <abramo@alsa-project.org>
6 * \date 2000-2001
7 */
8 /*
9 * PCM - A-Law conversion
10 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
11 *
12 *
13 * This library is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License as
15 * published by the Free Software Foundation; either version 2.1 of
16 * the License, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 *
27 */
28
29 #include "bswap.h"
30 #include "pcm_local.h"
31 #include "pcm_plugin.h"
32
33 #include "plugin_ops.h"
34
35 #ifndef PIC
36 /* entry for static linking */
37 const char *_snd_module_pcm_alaw = "";
38 #endif
39
40 #ifndef DOC_HIDDEN
41
42 typedef void (*alaw_f)(const snd_pcm_channel_area_t *dst_areas,
43 snd_pcm_uframes_t dst_offset,
44 const snd_pcm_channel_area_t *src_areas,
45 snd_pcm_uframes_t src_offset,
46 unsigned int channels, snd_pcm_uframes_t frames,
47 unsigned int getputidx);
48
49 typedef struct {
50 /* This field need to be the first */
51 snd_pcm_plugin_t plug;
52 unsigned int getput_idx;
53 alaw_f func;
54 snd_pcm_format_t sformat;
55 } snd_pcm_alaw_t;
56
57 #endif
58
val_seg(int val)59 static inline int val_seg(int val)
60 {
61 int r = 1;
62 val >>= 8;
63 if (val & 0xf0) {
64 val >>= 4;
65 r += 4;
66 }
67 if (val & 0x0c) {
68 val >>= 2;
69 r += 2;
70 }
71 if (val & 0x02)
72 r += 1;
73 return r;
74 }
75
76 /*
77 * s16_to_alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
78 *
79 * s16_to_alaw() accepts an 16-bit integer and encodes it as A-law data.
80 *
81 * Linear Input Code Compressed Code
82 * ------------------------ ---------------
83 * 0000000wxyza 000wxyz
84 * 0000001wxyza 001wxyz
85 * 000001wxyzab 010wxyz
86 * 00001wxyzabc 011wxyz
87 * 0001wxyzabcd 100wxyz
88 * 001wxyzabcde 101wxyz
89 * 01wxyzabcdef 110wxyz
90 * 1wxyzabcdefg 111wxyz
91 *
92 * For further information see John C. Bellamy's Digital Telephony, 1982,
93 * John Wiley & Sons, pps 98-111 and 472-476.
94 */
95
s16_to_alaw(int pcm_val)96 static unsigned char s16_to_alaw(int pcm_val)
97 {
98 int mask;
99 int seg;
100 unsigned char aval;
101
102 if (pcm_val >= 0) {
103 mask = 0xD5;
104 } else {
105 mask = 0x55;
106 pcm_val = -pcm_val;
107 if (pcm_val > 0x7fff)
108 pcm_val = 0x7fff;
109 }
110
111 if (pcm_val < 256)
112 aval = pcm_val >> 4;
113 else {
114 /* Convert the scaled magnitude to segment number. */
115 seg = val_seg(pcm_val);
116 aval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f);
117 }
118 return aval ^ mask;
119 }
120
121 /*
122 * alaw_to_s16() - Convert an A-law value to 16-bit linear PCM
123 *
124 */
alaw_to_s16(unsigned char a_val)125 static int alaw_to_s16(unsigned char a_val)
126 {
127 int t;
128 int seg;
129
130 a_val ^= 0x55;
131 t = a_val & 0x7f;
132 if (t < 16)
133 t = (t << 4) + 8;
134 else {
135 seg = (t >> 4) & 0x07;
136 t = ((t & 0x0f) << 4) + 0x108;
137 t <<= seg -1;
138 }
139 return ((a_val & 0x80) ? t : -t);
140 }
141
142 #ifndef DOC_HIDDEN
143
snd_pcm_alaw_decode(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,unsigned int putidx)144 void snd_pcm_alaw_decode(const snd_pcm_channel_area_t *dst_areas,
145 snd_pcm_uframes_t dst_offset,
146 const snd_pcm_channel_area_t *src_areas,
147 snd_pcm_uframes_t src_offset,
148 unsigned int channels, snd_pcm_uframes_t frames,
149 unsigned int putidx)
150 {
151 #define PUT16_LABELS
152 #include "plugin_ops.h"
153 #undef PUT16_LABELS
154 void *put = put16_labels[putidx];
155 unsigned int channel;
156 for (channel = 0; channel < channels; ++channel) {
157 const unsigned char *src;
158 char *dst;
159 int src_step, dst_step;
160 snd_pcm_uframes_t frames1;
161 const snd_pcm_channel_area_t *src_area = &src_areas[channel];
162 const snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
163 src = snd_pcm_channel_area_addr(src_area, src_offset);
164 dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
165 src_step = snd_pcm_channel_area_step(src_area);
166 dst_step = snd_pcm_channel_area_step(dst_area);
167 frames1 = frames;
168 while (frames1-- > 0) {
169 int16_t sample = alaw_to_s16(*src);
170 goto *put;
171 #define PUT16_END after
172 #include "plugin_ops.h"
173 #undef PUT16_END
174 after:
175 src += src_step;
176 dst += dst_step;
177 }
178 }
179 }
180
snd_pcm_alaw_encode(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,unsigned int getidx)181 void snd_pcm_alaw_encode(const snd_pcm_channel_area_t *dst_areas,
182 snd_pcm_uframes_t dst_offset,
183 const snd_pcm_channel_area_t *src_areas,
184 snd_pcm_uframes_t src_offset,
185 unsigned int channels, snd_pcm_uframes_t frames,
186 unsigned int getidx)
187 {
188 #define GET16_LABELS
189 #include "plugin_ops.h"
190 #undef GET16_LABELS
191 void *get = get16_labels[getidx];
192 unsigned int channel;
193 int16_t sample = 0;
194 for (channel = 0; channel < channels; ++channel) {
195 const char *src;
196 char *dst;
197 int src_step, dst_step;
198 snd_pcm_uframes_t frames1;
199 const snd_pcm_channel_area_t *src_area = &src_areas[channel];
200 const snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
201 src = snd_pcm_channel_area_addr(src_area, src_offset);
202 dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
203 src_step = snd_pcm_channel_area_step(src_area);
204 dst_step = snd_pcm_channel_area_step(dst_area);
205 frames1 = frames;
206 while (frames1-- > 0) {
207 goto *get;
208 #define GET16_END after
209 #include "plugin_ops.h"
210 #undef GET16_END
211 after:
212 *dst = s16_to_alaw(sample);
213 src += src_step;
214 dst += dst_step;
215 }
216 }
217 }
218
219 #endif /* DOC_HIDDEN */
220
snd_pcm_alaw_hw_refine_cprepare(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)221 static int snd_pcm_alaw_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
222 {
223 snd_pcm_alaw_t *alaw = pcm->private_data;
224 int err;
225 snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM };
226 err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS,
227 &access_mask);
228 if (err < 0)
229 return err;
230 if (alaw->sformat == SND_PCM_FORMAT_A_LAW) {
231 snd_pcm_format_mask_t format_mask = { SND_PCM_FMTBIT_LINEAR };
232 err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT,
233 &format_mask);
234 } else {
235 err = _snd_pcm_hw_params_set_format(params,
236 SND_PCM_FORMAT_A_LAW);
237 }
238 if (err < 0)
239 return err;
240 err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD);
241 if (err < 0)
242 return err;
243 params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
244 return 0;
245 }
246
snd_pcm_alaw_hw_refine_sprepare(snd_pcm_t * pcm,snd_pcm_hw_params_t * sparams)247 static int snd_pcm_alaw_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
248 {
249 snd_pcm_alaw_t *alaw = pcm->private_data;
250 snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP };
251 _snd_pcm_hw_params_any(sparams);
252 _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
253 &saccess_mask);
254 _snd_pcm_hw_params_set_format(sparams, alaw->sformat);
255 _snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD);
256 return 0;
257 }
258
snd_pcm_alaw_hw_refine_schange(snd_pcm_t * pcm ATTRIBUTE_UNUSED,snd_pcm_hw_params_t * params,snd_pcm_hw_params_t * sparams)259 static int snd_pcm_alaw_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
260 snd_pcm_hw_params_t *sparams)
261 {
262 int err;
263 unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
264 SND_PCM_HW_PARBIT_RATE |
265 SND_PCM_HW_PARBIT_PERIOD_SIZE |
266 SND_PCM_HW_PARBIT_BUFFER_SIZE |
267 SND_PCM_HW_PARBIT_PERIODS |
268 SND_PCM_HW_PARBIT_PERIOD_TIME |
269 SND_PCM_HW_PARBIT_BUFFER_TIME |
270 SND_PCM_HW_PARBIT_TICK_TIME);
271 err = _snd_pcm_hw_params_refine(sparams, links, params);
272 if (err < 0)
273 return err;
274 return 0;
275 }
276
snd_pcm_alaw_hw_refine_cchange(snd_pcm_t * pcm ATTRIBUTE_UNUSED,snd_pcm_hw_params_t * params,snd_pcm_hw_params_t * sparams)277 static int snd_pcm_alaw_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
278 snd_pcm_hw_params_t *sparams)
279 {
280 int err;
281 unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
282 SND_PCM_HW_PARBIT_RATE |
283 SND_PCM_HW_PARBIT_PERIOD_SIZE |
284 SND_PCM_HW_PARBIT_BUFFER_SIZE |
285 SND_PCM_HW_PARBIT_PERIODS |
286 SND_PCM_HW_PARBIT_PERIOD_TIME |
287 SND_PCM_HW_PARBIT_BUFFER_TIME |
288 SND_PCM_HW_PARBIT_TICK_TIME);
289 err = _snd_pcm_hw_params_refine(params, links, sparams);
290 if (err < 0)
291 return err;
292 return 0;
293 }
294
snd_pcm_alaw_hw_refine(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)295 static int snd_pcm_alaw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
296 {
297 return snd_pcm_hw_refine_slave(pcm, params,
298 snd_pcm_alaw_hw_refine_cprepare,
299 snd_pcm_alaw_hw_refine_cchange,
300 snd_pcm_alaw_hw_refine_sprepare,
301 snd_pcm_alaw_hw_refine_schange,
302 snd_pcm_generic_hw_refine);
303 }
304
snd_pcm_alaw_hw_params(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)305 static int snd_pcm_alaw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
306 {
307 snd_pcm_alaw_t *alaw = pcm->private_data;
308 snd_pcm_format_t format;
309 int err = snd_pcm_hw_params_slave(pcm, params,
310 snd_pcm_alaw_hw_refine_cchange,
311 snd_pcm_alaw_hw_refine_sprepare,
312 snd_pcm_alaw_hw_refine_schange,
313 snd_pcm_generic_hw_params);
314 if (err < 0)
315 return err;
316
317 err = INTERNAL(snd_pcm_hw_params_get_format)(params, &format);
318 if (err < 0)
319 return err;
320
321 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
322 if (alaw->sformat == SND_PCM_FORMAT_A_LAW) {
323 alaw->getput_idx = snd_pcm_linear_get_index(format, SND_PCM_FORMAT_S16);
324 alaw->func = snd_pcm_alaw_encode;
325 } else {
326 alaw->getput_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, alaw->sformat);
327 alaw->func = snd_pcm_alaw_decode;
328 }
329 } else {
330 if (alaw->sformat == SND_PCM_FORMAT_A_LAW) {
331 alaw->getput_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, format);
332 alaw->func = snd_pcm_alaw_decode;
333 } else {
334 alaw->getput_idx = snd_pcm_linear_get_index(alaw->sformat, SND_PCM_FORMAT_S16);
335 alaw->func = snd_pcm_alaw_encode;
336 }
337 }
338 return 0;
339 }
340
341 static snd_pcm_uframes_t
snd_pcm_alaw_write_areas(snd_pcm_t * pcm,const snd_pcm_channel_area_t * areas,snd_pcm_uframes_t offset,snd_pcm_uframes_t size,const snd_pcm_channel_area_t * slave_areas,snd_pcm_uframes_t slave_offset,snd_pcm_uframes_t * slave_sizep)342 snd_pcm_alaw_write_areas(snd_pcm_t *pcm,
343 const snd_pcm_channel_area_t *areas,
344 snd_pcm_uframes_t offset,
345 snd_pcm_uframes_t size,
346 const snd_pcm_channel_area_t *slave_areas,
347 snd_pcm_uframes_t slave_offset,
348 snd_pcm_uframes_t *slave_sizep)
349 {
350 snd_pcm_alaw_t *alaw = pcm->private_data;
351 if (size > *slave_sizep)
352 size = *slave_sizep;
353 alaw->func(slave_areas, slave_offset,
354 areas, offset,
355 pcm->channels, size,
356 alaw->getput_idx);
357 *slave_sizep = size;
358 return size;
359 }
360
361 static snd_pcm_uframes_t
snd_pcm_alaw_read_areas(snd_pcm_t * pcm,const snd_pcm_channel_area_t * areas,snd_pcm_uframes_t offset,snd_pcm_uframes_t size,const snd_pcm_channel_area_t * slave_areas,snd_pcm_uframes_t slave_offset,snd_pcm_uframes_t * slave_sizep)362 snd_pcm_alaw_read_areas(snd_pcm_t *pcm,
363 const snd_pcm_channel_area_t *areas,
364 snd_pcm_uframes_t offset,
365 snd_pcm_uframes_t size,
366 const snd_pcm_channel_area_t *slave_areas,
367 snd_pcm_uframes_t slave_offset,
368 snd_pcm_uframes_t *slave_sizep)
369 {
370 snd_pcm_alaw_t *alaw = pcm->private_data;
371 if (size > *slave_sizep)
372 size = *slave_sizep;
373 alaw->func(areas, offset,
374 slave_areas, slave_offset,
375 pcm->channels, size,
376 alaw->getput_idx);
377 *slave_sizep = size;
378 return size;
379 }
380
snd_pcm_alaw_dump(snd_pcm_t * pcm,snd_output_t * out)381 static void snd_pcm_alaw_dump(snd_pcm_t *pcm, snd_output_t *out)
382 {
383 snd_pcm_alaw_t *alaw = pcm->private_data;
384 snd_output_printf(out, "A-Law conversion PCM (%s)\n",
385 snd_pcm_format_name(alaw->sformat));
386 if (pcm->setup) {
387 snd_output_printf(out, "Its setup is:\n");
388 snd_pcm_dump_setup(pcm, out);
389 }
390 snd_output_printf(out, "Slave: ");
391 snd_pcm_dump(alaw->plug.gen.slave, out);
392 }
393
394 static const snd_pcm_ops_t snd_pcm_alaw_ops = {
395 .close = snd_pcm_generic_close,
396 .info = snd_pcm_generic_info,
397 .hw_refine = snd_pcm_alaw_hw_refine,
398 .hw_params = snd_pcm_alaw_hw_params,
399 .hw_free = snd_pcm_generic_hw_free,
400 .sw_params = snd_pcm_generic_sw_params,
401 .channel_info = snd_pcm_generic_channel_info,
402 .dump = snd_pcm_alaw_dump,
403 .nonblock = snd_pcm_generic_nonblock,
404 .async = snd_pcm_generic_async,
405 .mmap = snd_pcm_generic_mmap,
406 .munmap = snd_pcm_generic_munmap,
407 .query_chmaps = snd_pcm_generic_query_chmaps,
408 .get_chmap = snd_pcm_generic_get_chmap,
409 .set_chmap = snd_pcm_generic_set_chmap,
410 };
411
412 /**
413 * \brief Creates a new A-Law conversion PCM
414 * \param pcmp Returns created PCM handle
415 * \param name Name of PCM
416 * \param sformat Slave (destination) format
417 * \param slave Slave PCM handle
418 * \param close_slave When set, the slave PCM handle is closed with copy PCM
419 * \retval zero on success otherwise a negative error code
420 * \warning Using of this function might be dangerous in the sense
421 * of compatibility reasons. The prototype might be freely
422 * changed in future.
423 */
snd_pcm_alaw_open(snd_pcm_t ** pcmp,const char * name,snd_pcm_format_t sformat,snd_pcm_t * slave,int close_slave)424 int snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sformat, snd_pcm_t *slave, int close_slave)
425 {
426 snd_pcm_t *pcm;
427 snd_pcm_alaw_t *alaw;
428 int err;
429 assert(pcmp && slave);
430 if (snd_pcm_format_linear(sformat) != 1 &&
431 sformat != SND_PCM_FORMAT_A_LAW)
432 return -EINVAL;
433 alaw = calloc(1, sizeof(snd_pcm_alaw_t));
434 if (!alaw) {
435 return -ENOMEM;
436 }
437 snd_pcm_plugin_init(&alaw->plug);
438 alaw->sformat = sformat;
439 alaw->plug.read = snd_pcm_alaw_read_areas;
440 alaw->plug.write = snd_pcm_alaw_write_areas;
441 alaw->plug.undo_read = snd_pcm_plugin_undo_read_generic;
442 alaw->plug.undo_write = snd_pcm_plugin_undo_write_generic;
443 alaw->plug.gen.slave = slave;
444 alaw->plug.gen.close_slave = close_slave;
445
446 err = snd_pcm_new(&pcm, SND_PCM_TYPE_ALAW, name, slave->stream, slave->mode);
447 if (err < 0) {
448 free(alaw);
449 return err;
450 }
451 pcm->ops = &snd_pcm_alaw_ops;
452 pcm->fast_ops = &snd_pcm_plugin_fast_ops;
453 pcm->private_data = alaw;
454 pcm->poll_fd = slave->poll_fd;
455 pcm->poll_events = slave->poll_events;
456 pcm->tstamp_type = slave->tstamp_type;
457 snd_pcm_set_hw_ptr(pcm, &alaw->plug.hw_ptr, -1, 0);
458 snd_pcm_set_appl_ptr(pcm, &alaw->plug.appl_ptr, -1, 0);
459 *pcmp = pcm;
460
461 return 0;
462 }
463
464 /*! \page pcm_plugins
465
466 \section pcm_plugins_alaw Plugin: A-Law
467
468 This plugin converts A-Law samples to linear or linear to A-Law samples
469 from master A-Law conversion PCM to given slave PCM. The channel count,
470 format and rate must match for both of them.
471
472 \code
473 pcm.name {
474 type alaw # A-Law conversion PCM
475 slave STR # Slave name
476 # or
477 slave { # Slave definition
478 pcm STR # Slave PCM name
479 # or
480 pcm { } # Slave PCM definition
481 format STR # Slave format
482 }
483 }
484 \endcode
485
486 \subsection pcm_plugins_alaw_funcref Function reference
487
488 <UL>
489 <LI>snd_pcm_alaw_open()
490 <LI>_snd_pcm_alaw_open()
491 </UL>
492
493 */
494
495 /**
496 * \brief Creates a new A-Law conversion PCM
497 * \param pcmp Returns created PCM handle
498 * \param name Name of PCM
499 * \param root Root configuration node
500 * \param conf Configuration node with copy PCM description
501 * \param stream Stream type
502 * \param mode Stream mode
503 * \retval zero on success otherwise a negative error code
504 * \warning Using of this function might be dangerous in the sense
505 * of compatibility reasons. The prototype might be freely
506 * changed in future.
507 */
_snd_pcm_alaw_open(snd_pcm_t ** pcmp,const char * name,snd_config_t * root,snd_config_t * conf,snd_pcm_stream_t stream,int mode)508 int _snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name,
509 snd_config_t *root, snd_config_t *conf,
510 snd_pcm_stream_t stream, int mode)
511 {
512 snd_config_iterator_t i, next;
513 int err;
514 snd_pcm_t *spcm;
515 snd_config_t *slave = NULL, *sconf;
516 snd_pcm_format_t sformat;
517 snd_config_for_each(i, next, conf) {
518 snd_config_t *n = snd_config_iterator_entry(i);
519 const char *id;
520 if (snd_config_get_id(n, &id) < 0)
521 continue;
522 if (snd_pcm_conf_generic_id(id))
523 continue;
524 if (strcmp(id, "slave") == 0) {
525 slave = n;
526 continue;
527 }
528 SNDERR("Unknown field %s", id);
529 return -EINVAL;
530 }
531 if (!slave) {
532 SNDERR("slave is not defined");
533 return -EINVAL;
534 }
535 err = snd_pcm_slave_conf(root, slave, &sconf, 1,
536 SND_PCM_HW_PARAM_FORMAT, SCONF_MANDATORY, &sformat);
537 if (err < 0)
538 return err;
539 if (snd_pcm_format_linear(sformat) != 1 &&
540 sformat != SND_PCM_FORMAT_A_LAW) {
541 snd_config_delete(sconf);
542 SNDERR("invalid slave format");
543 return -EINVAL;
544 }
545 err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
546 snd_config_delete(sconf);
547 if (err < 0)
548 return err;
549 err = snd_pcm_alaw_open(pcmp, name, sformat, spcm, 1);
550 if (err < 0)
551 snd_pcm_close(spcm);
552 return err;
553 }
554 #ifndef DOC_HIDDEN
555 SND_DLSYM_BUILD_VERSION(_snd_pcm_alaw_open, SND_PCM_DLSYM_VERSION);
556 #endif
557