1 /** OpenCP Module Player
2 * copyright (c) '94-'21 Stian Skjelstad <stian.skjelstad@gmail.com>
3 *
4 * ALSA (Advanced Linux Sound Architecture) Player device
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21
22 #include "config.h"
23 #define ALSA_PCM_NEW_HW_PARAMS_API
24 #define ALSA_PCM_NEW_SW_PARAMS_API
25 #include <alsa/asoundlib.h>
26 #include <alsa/mixer.h>
27 #include <alsa/pcm.h>
28 #include <alsa/pcm_plugin.h>
29 #include <string.h>
30 #include "types.h"
31 #include "boot/plinkman.h"
32 #include "boot/psetting.h"
33 #include "cpiface/vol.h"
34 #include "dev/imsdev.h"
35 #include "dev/player.h"
36 #include "filesel/dirdb.h"
37 #include "filesel/filesystem.h"
38 #include "filesel/filesystem-drive.h"
39 #include "filesel/filesystem-file-mem.h"
40 #include "filesel/filesystem-setup.h"
41 #include "filesel/mdb.h"
42 #include "filesel/modlist.h"
43 #include "filesel/pfilesel.h"
44 #include "stuff/framelock.h"
45 #include "stuff/imsrtns.h"
46 #include "stuff/poutput.h"
47
48 //#define ALSA_DEBUG_OUTPUT 1
49 //#define ALSA_DEBUG 1
50 #ifdef ALSA_DEBUG_OUTPUT
51 static int debug_output = -1;
52 #endif
53 #ifdef ALSA_DEBUG
54 #define debug_printf(...) fprintf (stderr, __VA_ARGS__)
55 #else
56 #define debug_printf(format, args...) ((void)0)
57 #endif
58
59 static struct interfacestruct alsaPCMoutIntr;
60
61 static snd_pcm_t *alsa_pcm = NULL;
62 static snd_mixer_t *mixer = NULL;
63
64 static snd_pcm_status_t *alsa_pcm_status=NULL;
65 #if SND_LIB_VERSION < 0x01000e
66 #error Minimum version of libasound2 is 1.0.14
67 #endif
68
69 static snd_pcm_hw_params_t *hwparams = NULL;
70 static snd_pcm_sw_params_t *swparams = NULL;
71
72 struct sounddevice plrAlsa;
73 /*static struct deviceinfo currentcard;*/
74 static struct ocpdir_t dir_alsa;
75
76 static void alsaOpenDevice(void);
77
78 static char alsaCardName[DEVICE_NAME_MAX+1];
79 static char alsaMixerName[DEVICE_NAME_MAX+1];
80
81 /* stolen from devposs */
82 #define MAX_ALSA_MIXER 256
83 static char *playbuf;
84 static int buflen; /* in bytes */
85 static volatile int kernpos, cachepos, bufpos; /* in bytes */
86 static volatile int cachelen, kernlen; /* to make life easier */
87 static struct ocpvolstruct mixer_entries[MAX_ALSA_MIXER];
88 static int alsa_mixers_n=0;
89 /* playbuf kernpos cachepos bufpos buflen
90 * | | kernlen | cachelen | |
91 *
92 * on flush, we update all variables> * on getbufpos we return kernpos-(1 sample) as safe point to buffer up to
93 * on getplaypos we use last known kernpos if locked, else update kernpos
94 */
95
96 static volatile uint32_t playpos; /* how many samples have we done totally */
97 static int stereo;
98 static int bit16;
99
100 static volatile int busy=0;
101
102 #warning fix-me!!!!
103 uint32_t custom_dsp_mdb_ref=0xffffffff;
104 uint32_t custom_mixer_mdb_ref=0xffffffff;
105
106
mlDrawBox(void)107 static int mlDrawBox(void)
108 {
109 int mlTop=plScrHeight/2-2;
110 unsigned int i;
111
112 displayvoid(mlTop+1, 5, plScrWidth-10);
113 displayvoid(mlTop+2, 5, plScrWidth-10);
114 displayvoid(mlTop+3, 5, plScrWidth-10);
115 displaystr(mlTop, 4, 0x04, "\xda", 1);
116 for (i=5;i<(plScrWidth-5);i++)
117 displaystr(mlTop, i, 0x04, "\xc4", 1);
118 displaystr(mlTop, plScrWidth-5, 0x04, "\xbf", 1);
119 displaystr(mlTop+1, 4, 0x04, "\xb3", 1);
120 displaystr(mlTop+2, 4, 0x04, "\xb3", 1);
121 displaystr(mlTop+3, 4, 0x04, "\xb3", 1);
122 displaystr(mlTop+1, plScrWidth-5, 0x04, "\xb3", 1);
123 displaystr(mlTop+2, plScrWidth-5, 0x04, "\xb3", 1);
124 displaystr(mlTop+3, plScrWidth-5, 0x04, "\xb3", 1);
125 displaystr(mlTop+4, 4, 0x04, "\xc0", 1);
126 for (i=5;i<(plScrWidth-5);i++)
127 displaystr(mlTop+4, i, 0x04, "\xc4", 1);
128 displaystr(mlTop+4, plScrWidth-5, 0x04, "\xd9", 1);
129
130 return mlTop;
131 }
132 /* stolen from devposs */
getbufpos(void)133 static int getbufpos(void)
134 {
135 int retval;
136
137 if (busy++)
138 {
139 /* can't escape if already set, and shouldn't happen */
140 }
141
142 if (kernpos==bufpos)
143 {
144 if (cachelen|kernlen)
145 {
146 retval=kernpos;
147 busy--;
148 return retval;
149 }
150 }
151 /*
152 if ((!cachelen)&&(!kernlen))
153 retval=(kernpos+buflen-(0<<(bit16+stereo)))%buflen;
154 else*/
155 retval=(kernpos+buflen-(1<<(bit16+stereo)))%buflen;
156 busy--;
157 return retval;
158 }
159 /* more or less stolen from devposs */
getplaypos(void)160 static int getplaypos(void)
161 {
162 int retval;
163
164 if (busy++)
165 {
166 } else {
167 snd_pcm_sframes_t tmp;
168 int err;
169
170 debug_printf("ALSA_getplaypos()\n");
171
172 err=snd_pcm_status(alsa_pcm, alsa_pcm_status);
173 debug_printf(" snd_pcm_status(alsa_pcm, alsa_pcm_status) = %s\n", snd_strerror(-err));
174
175 if (err < 0)
176 {
177 fprintf(stderr, "ALSA: snd_pcm_status() failed: %s\n", snd_strerror(-err));
178 } else {
179 tmp=snd_pcm_status_get_delay(alsa_pcm_status);
180
181 debug_printf(" snd_pcm_status_get_delay(alsa_pcm_status = %d\n", (int)tmp);
182 if (tmp<0)
183 { /* we ignore buffer-underruns */
184 tmp=0;
185 } else if (tmp==0)
186 { /* ALSA sometimes (atlast on Stians Ubuntu laptop) gives odelay==0 always */
187 snd_pcm_sframes_t tmp1 = snd_pcm_status_get_avail_max(alsa_pcm_status);
188 snd_pcm_sframes_t tmp2 = snd_pcm_status_get_avail(alsa_pcm_status);
189 tmp = tmp1 - tmp2;
190
191 debug_printf(" (no delay available) fallback:\n");
192 debug_printf(" snd_pcm_status_get_avail_max() = %d\n", (int)tmp1);
193 debug_printf(" snd_pcm_status_get_avail() = %d\n", (int)tmp2);
194 debug_printf(" => %d\n", (int)tmp);
195
196 if (tmp<0)
197 {
198 tmp=0;
199 }
200 }
201 tmp<<=(bit16+stereo);
202
203 if (tmp<kernlen)
204 {
205 kernlen=tmp;
206 }
207 kernpos=(cachepos-kernlen+buflen)%buflen;
208 }
209 }
210 retval=kernpos;
211 busy--;
212
213 debug_printf(" => %d\n", retval);
214
215 return retval;
216 }
217
218 /* more or less stolen from devposs */
flush(void)219 static void flush(void)
220 {
221 int result, n, odelay, tmp;
222 int err;
223
224 if (busy++)
225 {
226 busy--;
227 return;
228 }
229
230 debug_printf("ALSA_flush()\n");
231
232 err=snd_pcm_status(alsa_pcm, alsa_pcm_status);
233 debug_printf(" snd_pcm_status(alsa_pcm, alsa_pcm_status) = %s\n", snd_strerror(-err));
234 if (err<0)
235 {
236 fprintf(stderr, "ALSA: snd_pcm_status() failed: %s\n", snd_strerror(-err));
237 busy--;
238 return;
239 }
240
241 odelay=snd_pcm_status_get_delay(alsa_pcm_status);
242 debug_printf(" snd_pcm_status_get_delay(alsa_pcm_status) = %d\n", odelay);
243
244 if (odelay<0)
245 { /* we ignore buffer-underruns */
246 odelay=0;
247 } else if (odelay==0)
248 { /* ALSA sometimes (atlast on Stians Ubuntu laptop) gives odelay==0 always */
249 snd_pcm_sframes_t tmp1 = snd_pcm_status_get_avail_max(alsa_pcm_status);
250 snd_pcm_sframes_t tmp2 = snd_pcm_status_get_avail(alsa_pcm_status);
251 odelay = tmp1 - tmp2;
252
253 debug_printf(" (no delay available) fallback:\n");
254 debug_printf(" snd_pcm_status_get_avail_max() = %d\n", (int)tmp1);
255 debug_printf(" snd_pcm_status_get_avail() = %d\n", (int)tmp2);
256 debug_printf(" => %d\n", (int)odelay);
257
258 if (odelay<0)
259 {
260 odelay=0;
261 }
262 }
263 odelay<<=(bit16+stereo);
264
265 if (odelay>kernlen)
266 {
267 odelay=kernlen;
268 } else if ((odelay<kernlen))
269 {
270 kernlen=odelay;
271 kernpos=(cachepos-kernlen+buflen)%buflen;
272 }
273
274 if (!cachelen)
275 {
276 busy--;
277 return;
278 }
279
280 if (bufpos<=cachepos)
281 n=buflen-cachepos;
282 else
283 n=bufpos-cachepos;
284
285 /* TODO, check kernel-size
286 if (n>info.bytes)
287 n=info.bytes;
288 */
289
290 if (n<=0)
291 {
292 busy--;
293 return;
294 }
295
296 tmp = snd_pcm_status_get_avail(alsa_pcm_status);
297
298 debug_printf (" snd_pcm_status_get_avail() = %d\n", tmp);
299
300 tmp = tmp << (bit16+stereo);
301
302 if (n > tmp)
303 {
304 n = tmp;
305 }
306 result=snd_pcm_writei(alsa_pcm, playbuf+cachepos, n>>(bit16+stereo));
307
308 debug_printf (" snd_pcm_writei (%d) = %d\n", n>>(bit16+stereo), result);
309
310 #ifdef ALSA_DEBUG_OUTPUT
311 if (result > 0)
312 {
313 if (debug_output >= 0)
314 {
315 write (debug_output, playbuf+cachepos, result<<(bit16+stereo));
316 }
317 }
318 #endif
319 if (result<0)
320 {
321 if (result==-EPIPE)
322 {
323 fprintf(stderr, "ALSA: Machine is too slow, calling snd_pcm_prepare()\n");
324 snd_pcm_prepare(alsa_pcm); /* TODO, can this fail? */
325 debug_printf (" snd_pcm_prepare()\n");
326 }
327 busy--;
328 return;
329 }
330 result<<=(bit16+stereo);
331 cachepos=(cachepos+result+buflen)%buflen;
332 playpos+=result;
333 cachelen-=result;
334 kernlen+=result;
335
336 busy--;
337 }
338 /* stolen from devposs */
advance(unsigned int pos)339 static void advance(unsigned int pos)
340 {
341 debug_printf ("ALSA_advance: oldpos=%d newpos=%d add=%d (busy=%d)\n", bufpos, pos, (pos-bufpos+buflen)%buflen, busy);
342
343 busy++;
344
345 cachelen+=(pos-bufpos+buflen)%buflen;
346 bufpos=pos;
347
348 debug_printf (" cachelen=%d kernlen=%d sum=%d len=%d\n", cachelen, kernlen, cachelen+kernlen, buflen);
349
350 busy--;
351 }
352 /* stolen from devposs */
gettimer(void)353 static uint32_t gettimer(void)
354 {
355 long tmp=playpos;
356 int odelay;
357
358 if (busy++)
359 {
360 odelay=kernlen;
361 } else {
362 int err;
363
364 debug_printf("ALSA_gettimer()");
365
366 err=snd_pcm_status(alsa_pcm, alsa_pcm_status);
367
368 debug_printf (" snd_pcm_status(alsa_pcm, alsa_pcm_status) = %s\n", snd_strerror(-err));
369
370 if (err<0)
371 {
372 fprintf(stderr, "ALSA: snd_pcm_status() failed: %s\n", snd_strerror(-err));
373 odelay=kernlen;
374 } else {
375
376 odelay=snd_pcm_status_get_delay(alsa_pcm_status);
377 debug_printf (" snd_pcm_status_get_delay() = %d\n", odelay);
378
379 if (odelay<0)
380 { /* we ignore buffer-underruns */
381 odelay=0;
382 } else if (odelay==0)
383 { /* ALSA sometimes (atlast on Stians Ubuntu laptop) gives odelay==0 always */
384 snd_pcm_sframes_t tmp1 = snd_pcm_status_get_avail_max(alsa_pcm_status);
385 snd_pcm_sframes_t tmp2 = snd_pcm_status_get_avail(alsa_pcm_status);
386 odelay = tmp1 - tmp2;
387
388 debug_printf(" (no delay available) fallback:\n");
389 debug_printf(" snd_pcm_status_get_avail_max() = %d\n", (int)tmp1);
390 debug_printf(" snd_pcm_status_get_avail() = %d\n", (int)tmp2);
391 debug_printf(" => %d\n", (int)odelay);
392
393 if (odelay<0)
394 {
395 odelay=0;
396 }
397 }
398
399 odelay<<=(bit16+stereo);
400 if (odelay>kernlen)
401 {
402 odelay=kernlen;
403 } else if ((odelay<kernlen))
404 {
405 kernlen=odelay;
406 kernpos=(cachepos-kernlen+buflen)%buflen;
407 }
408 }
409 }
410
411 tmp-=odelay;
412 busy--;
413 return imuldiv(tmp, 65536>>(stereo+bit16), plrRate);
414 }
415
dir_alsa_ref(struct ocpdir_t * self)416 static void dir_alsa_ref (struct ocpdir_t *self)
417 {
418 debug_printf ("dir_alsa_ref() (dummy)\n");
419 }
dir_alsa_unref(struct ocpdir_t * self)420 static void dir_alsa_unref (struct ocpdir_t *self)
421 {
422 debug_printf ("dir_alsa_unref() (dummy)\n");
423 }
424
425 struct dirhandle_alsa_t
426 {
427 struct ocpdir_t *owner;
428 void *token;
429 void(*callback_file)(void *token, struct ocpfile_t *);
430
431 int i;
432 int count;
433 void **hints;
434 };
435
dir_alsa_readdir_start(struct ocpdir_t * self,void (* callback_file)(void * token,struct ocpfile_t *),void (* callback_dir)(void * token,struct ocpdir_t *),void * token)436 static ocpdirhandle_pt dir_alsa_readdir_start (struct ocpdir_t *self, void(*callback_file)(void *token, struct ocpfile_t *),
437 void(*callback_dir )(void *token, struct ocpdir_t *), void *token)
438 {
439 int result;
440 struct dirhandle_alsa_t *retval = calloc (1, sizeof *retval);
441
442 if (!retval)
443 {
444 return 0;
445 }
446
447 debug_printf ("dir_alsa_readdir_start()\n");
448
449 result=snd_device_name_hint(-1, "pcm", &retval->hints);
450 debug_printf (" snd_device_name_hint() = %s\n", snd_strerror(-result));
451 if (result)
452 {
453 free (retval); /* zero cards found */
454 return 0;
455 }
456
457 retval->owner = self;
458 retval->callback_file = callback_file;
459 retval->token = token;
460 retval->count = 1;
461
462 return retval;
463 }
464
dir_alsa_readdir_cancel(ocpdirhandle_pt _handle)465 static void dir_alsa_readdir_cancel (ocpdirhandle_pt _handle)
466 {
467 struct dirhandle_alsa_t *handle = (struct dirhandle_alsa_t *)_handle;
468
469 debug_printf ("dir_alsa_readdir_cancel()\n");
470
471 snd_device_name_free_hint (handle->hints);
472 free (handle);
473 }
474
dir_alsa_update_mdb(uint32_t dirdb_ref,const char * name,const char * descr)475 static void dir_alsa_update_mdb (uint32_t dirdb_ref, const char *name, const char *descr)
476 {
477 uint32_t mdb_ref;
478 struct moduleinfostruct mi;
479
480 mdb_ref = mdbGetModuleReference2 (dirdb_ref, strlen (alsaPCMoutIntr.name));
481 debug_printf (" mdbGetModuleReference2 (0x%08"PRIx32") => 0x%08"PRIx32"\n", dirdb_ref, mdb_ref);
482 if (mdb_ref == 0xffffffff)
483 {
484 return;
485 }
486
487 mdbGetModuleInfo (&mi, mdb_ref);
488 mi.flags1 &= ~MDB_VIRTUAL;
489 mi.channels=2;
490 snprintf(mi.modname, sizeof (mi.modname), "%s", name);
491 mi.composer[0] = 0;
492 mi.comment[0] = 0;
493
494 if (descr)
495 {
496 const char *n = strchr (descr, '\n');
497 if (n)
498 {
499 int len = n - descr + 1;
500 if (len >= sizeof(mi.composer))
501 {
502 len = sizeof(mi.composer);
503 }
504 snprintf(mi.composer, len, "%s", descr);
505 snprintf(mi.comment, sizeof (mi.comment), "%s", n + 1);
506 } else {
507 if (strlen(descr) > sizeof (mi.composer))
508 {
509 n = descr+strlen(descr)-1;
510 while (n-descr > 0)
511 {
512 if ((*n) != ' ')
513 {
514 n--;
515 continue;
516 }
517 if (n-descr >= sizeof(mi.composer))
518 {
519 n--;
520 continue;
521 }
522 snprintf(mi.composer, n-descr+1, "%s", descr);
523 snprintf(mi.comment, sizeof (mi.comment), "%s", n + 1);
524 break;
525 }
526 } else {
527 snprintf(mi.composer, sizeof(mi.composer), "%s", descr);
528 }
529 }
530 }
531 mi.modtype=mtDEVv;
532 mdbWriteModuleInfo(mdb_ref, &mi);
533 }
534
535
dir_alsa_readdir_iterate(ocpdirhandle_pt _handle)536 static int dir_alsa_readdir_iterate (ocpdirhandle_pt _handle)
537 {
538 struct dirhandle_alsa_t *handle = (struct dirhandle_alsa_t *)_handle;
539
540 debug_printf ("dir_alsa_readdir_iterate() (handle->hints[%d]=%p\n", handle->i, handle->hints[handle->i]);
541
542 if (handle->hints[handle->i])
543 {
544 char *name, *descr, *io;
545 char namebuffer[128];
546 uint32_t dirdb_ref;
547 struct ocpfile_t *child;
548
549 name = snd_device_name_get_hint(handle->hints[handle->i], "NAME");
550 descr = snd_device_name_get_hint(handle->hints[handle->i], "DESC");
551 io = snd_device_name_get_hint(handle->hints[handle->i], "IOID");
552
553 debug_printf ("snd_device_name_get_hint()\n");
554 debug_printf (" [%d] name=%s\n", handle->i, name?name:"(NULL)");
555 debug_printf (" desc=%s\n", descr?descr:"(NULL)");
556 debug_printf (" io=%s\n", io?io:"(IO)");
557
558 if (!name) /* should never happen */
559 {
560 goto end;
561 }
562 if (io && (!strcmp(io, "Input"))) /* ignore input only cards */
563 {
564 goto end;
565 }
566
567 #warning Ideal would be to link dirdb_ref and shortname in an API!!!!!!!!
568 // snprintf (namebuffer, sizeof (namebuffer), "ALSA-PCM-%s.dev", name);
569 snprintf (namebuffer, sizeof (namebuffer), "alsa-%03d.dev", handle->count);
570
571 dirdb_ref = dirdbFindAndRef (handle->owner->dirdb_ref, namebuffer, dirdb_use_file);
572
573 dir_alsa_update_mdb (handle->owner->dirdb_ref, name, descr);
574
575 child = mem_file_open (handle->owner, dirdb_ref, strdup (alsaPCMoutIntr.name), strlen (alsaPCMoutIntr.name));
576 child->is_nodetect = 1;
577 handle->callback_file (handle->token, child);
578 child->unref (child);
579 dirdbUnref (dirdb_ref, dirdb_use_file);
580 handle->count++;
581 end:
582 free (name);
583 free (descr);
584 free (io);
585
586 handle->i++;
587 return 1;
588 } else {
589 return 0;
590 }
591 }
592
dir_alsa_readdir_dir(struct ocpdir_t * _self,uint32_t dirdb_ref)593 static struct ocpdir_t *dir_alsa_readdir_dir (struct ocpdir_t *_self, uint32_t dirdb_ref)
594 {
595 /* this can not succeed */
596 return 0;
597 }
598
dir_alsa_readdir_file(struct ocpdir_t * _self,uint32_t dirdb_ref)599 static struct ocpfile_t *dir_alsa_readdir_file (struct ocpdir_t *_self, uint32_t dirdb_ref)
600 {
601 int result, i;
602 char *searchpath = 0;
603 uint32_t parent_dirdb_ref;
604 void **hints;
605 int count = 1;
606
607 debug_printf ("dir_alsa_readdir_file()\n");
608
609 /* assertion begin */
610 parent_dirdb_ref = dirdbGetParentAndRef (dirdb_ref, dirdb_use_file);
611 dirdbUnref (parent_dirdb_ref, dirdb_use_file);
612 if (parent_dirdb_ref != _self->dirdb_ref)
613 {
614 fprintf (stderr, "dir_alsa_readdir_file: dirdb_ref->parent is not the expected value\n");
615 return 0;
616 }
617 /* assertion end */
618
619 dirdbGetName_internalstr (dirdb_ref, &searchpath);
620 if (!searchpath)
621 {
622 return 0;
623 }
624
625 result=snd_device_name_hint(-1, "pcm", &hints);
626 debug_printf (" snd_device_name_hint() = %s\n", snd_strerror(-result));
627 if (result)
628 {
629 return 0;
630 }
631
632 for (i=0; hints[i]; i++)
633 {
634 char *name, *descr, *io;
635 char namebuffer[128];
636 struct ocpfile_t *child;
637
638 name = snd_device_name_get_hint (hints[i], "NAME");
639 descr = snd_device_name_get_hint (hints[i], "DESC");
640 io = snd_device_name_get_hint (hints[i], "IOID");
641
642 debug_printf ("snd_device_name_get_hint()\n");
643 debug_printf (" [%d] name=%s\n", i, name?name:"(NULL)");
644 debug_printf (" desc=%s\n", descr?descr:"(NULL)");
645 debug_printf (" io=%s\n", io?io:"(NULL)");
646
647 if (!name) /* should never happen */
648 {
649 free (descr);
650 free (io);
651 continue;
652 }
653 if (io && (!strcmp(io, "Input"))) /* ignore input only cards */
654 {
655 free (name);
656 free (descr);
657 free (io);
658 continue;
659 }
660
661 //struct modlistentry entry;
662 //memset(&entry, 0, sizeof(entry));
663 #if 0
664 snprintf(shortname, 4, "alsa-%03ddev", handle->count);
665 #else
666 //memcpy (shortname, "alsa-", 5);
667 //snprintf(shortname+5, 4, "%03d", handle->count);
668 //memcpy (shortname + 8, "dev", 3);
669 #endif
670 #warning Ideal would be to link dirdb_ref and shortname in an API!!!!!!!!
671 // snprintf(namebuffer, sizeof(namebuffer), "ALSA-PCM-%s.dev", name);
672 snprintf (namebuffer, sizeof (namebuffer), "alsa-%03d.dev", count);
673
674 if (strcmp (searchpath, namebuffer))
675 {
676 count++;
677 free (name);
678 free (descr);
679 free (io);
680 continue;
681 }
682
683 dir_alsa_update_mdb (dirdb_ref, name, descr);
684
685 free (name);
686 free (descr);
687 free (io);
688 snd_device_name_free_hint (hints);
689
690 child = mem_file_open (_self, dirdb_ref, strdup (alsaPCMoutIntr.name), strlen (alsaPCMoutIntr.name));
691 child->is_nodetect = 1;
692 return child;
693 }
694
695 snd_device_name_free_hint (hints);
696
697 return 0;
698 }
699
detect_cards(void)700 static int detect_cards (void)
701 {
702 int result;
703 int retval = 0;
704 int i;
705 void **hints = 0;
706
707 debug_printf ("ALSA_detect_card\n");
708
709 result=snd_device_name_hint(-1, "pcm", &hints);
710 debug_printf (" snd_device_name_hint() = %s\n", snd_strerror(-result));
711
712 if (result)
713 {
714 return retval; /* zero cards found */
715 }
716
717 for (i=0; hints[i]; i++)
718 {
719 char *name, *descr, *io;
720 name = snd_device_name_get_hint(hints[i], "NAME");
721 descr = snd_device_name_get_hint(hints[i], "DESC");
722 io = snd_device_name_get_hint(hints[i], "IOID");
723
724 debug_printf (" [%d] name=%s\n", i, name?name:"(NULL)");
725 debug_printf (" desc=%s\n", descr?descr:"(NULL)");
726 debug_printf (" io=%s\n", io?io:"(IO)");
727
728 if (!name) /* should never happen */
729 {
730 goto end;
731 }
732 if (io && (!strcmp(io, "Input"))) /* ignore input only cards */
733 {
734 goto end;
735 }
736
737 if (strcmp(name, "default"))
738 {
739 retval++;
740 }
741 end:
742 free (name);
743 free (descr);
744 free (io);
745 }
746
747 debug_printf (" snd_device_name_free_hint()\n");
748
749 snd_device_name_free_hint (hints);
750
751 debug_printf (" => %d\n", retval);
752
753 return retval;
754 }
755
756 /* plr API start */
757
SetOptions(unsigned int rate,int opt)758 static void SetOptions(unsigned int rate, int opt)
759 {
760 int err;
761 snd_pcm_format_t format;
762 unsigned int val;
763 /* start with setting default values, if we bail out */
764 plrRate=rate;
765 plrOpt=opt;
766
767 alsaOpenDevice();
768 if (!alsa_pcm)
769 return;
770
771 debug_printf ("ALSA_SetOptions (rate=%d, opt=0x%x%s%s)\n", rate, opt, (opt&PLR_16BIT)?" 16bit":" 8bit", (opt&PLR_SIGNEDOUT)?" signed":" unsigned");
772
773 err=snd_pcm_hw_params_any(alsa_pcm, hwparams);
774 debug_printf(" snd_pcm_hw_params_any(alsa_pcm, hwparams) = %s\n", snd_strerror(err<0?-err:0));
775 if (err<0)
776 {
777 fprintf(stderr, "ALSA: snd_pcm_hw_params_any() failed: %s\n", snd_strerror(-err));
778 return;
779 }
780
781 err=snd_pcm_hw_params_set_access(alsa_pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
782 debug_printf(" snd_pcm_hw_params_set_access(alsa_pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) = %s\n", snd_strerror(-err));
783 if (err)
784 {
785 fprintf(stderr, "ALSA: snd_pcm_hw_params_set_access() failed: %s\n", snd_strerror(-err));
786 return;
787 }
788
789 if (opt&PLR_16BIT)
790 {
791 if (opt&PLR_SIGNEDOUT)
792 {
793 format=SND_PCM_FORMAT_S16;
794 } else {
795 format=SND_PCM_FORMAT_U16;
796 }
797 } else {
798 if (opt&PLR_SIGNEDOUT)
799 {
800 format=SND_PCM_FORMAT_S8;
801 } else {
802 format=SND_PCM_FORMAT_U8;
803 }
804 }
805
806 err=snd_pcm_hw_params_set_format(alsa_pcm, hwparams, format);
807 debug_printf(" snd_pcm_hw_params_set_format(alsa_pcm, hwparams, format %i) = %s\n", format, snd_strerror(-err));
808 if (err)
809 {
810 err=snd_pcm_hw_params_set_format(alsa_pcm, hwparams, SND_PCM_FORMAT_S16);
811 debug_printf(" snd_pcm_hw_params_set_format(alsa_pcm, hwparams, SND_PCM_FORMAT_S16) = %s\n", snd_strerror(-err));
812 if (err==0)
813 {
814 opt|=PLR_16BIT|PLR_SIGNEDOUT;
815 } else {
816 err=snd_pcm_hw_params_set_format(alsa_pcm, hwparams, SND_PCM_FORMAT_U16);
817 debug_printf(" snd_pcm_hw_params_set_format(alsa_pcm, hwparams, SND_PCM_FORMAT_U16) = %s\n", snd_strerror(-err));
818 if (err==0)
819 {
820 opt&=~(PLR_16BIT|PLR_SIGNEDOUT);
821 opt|=PLR_16BIT;
822 } else {
823 err=snd_pcm_hw_params_set_format(alsa_pcm, hwparams, SND_PCM_FORMAT_S8);
824 debug_printf(" snd_pcm_hw_params_set_format(alsa_pcm, hwparams, SND_PCM_FORMAT_S8) = %s\n", snd_strerror(-err));
825 if (err==0)
826 {
827 opt&=~(PLR_16BIT|PLR_SIGNEDOUT);
828 opt|=PLR_SIGNEDOUT;
829 } else
830 {
831 err=snd_pcm_hw_params_set_format(alsa_pcm, hwparams, SND_PCM_FORMAT_U8);
832 debug_printf(" snd_pcm_hw_params_set_format(alsa_pcm, hwparams, SND_PCM_FORMAT_U8) = %s\n", snd_strerror(-err));
833 if (err==0)
834 {
835 opt&=~(PLR_16BIT|PLR_SIGNEDOUT);
836 } else {
837 fprintf(stderr, "ALSA: snd_pcm_hw_params_set_format() failed: %s\n", snd_strerror(-err));
838 return;
839 }
840 }
841 }
842 }
843 }
844
845 bit16=!!(opt&PLR_16BIT);
846 if (opt&PLR_STEREO)
847 {
848 val=2;
849 } else {
850 val=1;
851 }
852
853 err=snd_pcm_hw_params_set_channels_near(alsa_pcm, hwparams, &val);
854 debug_printf(" snd_pcm_hw_params_set_channels_near(alsa_pcm, hwparams, &channels=%i) = %s\n", val, snd_strerror(-err));
855 if (err<0)
856 {
857 fprintf(stderr, "ALSA: snd_pcm_hw_params_set_channels_near() failed: %s\n", snd_strerror(-err));
858 return;
859 }
860 if (val==1)
861 {
862 stereo=0;
863 opt&=~PLR_STEREO;
864 } else if (val==2)
865 {
866 stereo=1;
867 opt|=PLR_STEREO;
868 } else {
869 fprintf(stderr, "ALSA: snd_pcm_hw_params_set_channels_near() gave us %d channels\n", val);
870 return;
871 }
872
873 err=snd_pcm_hw_params_set_rate_near(alsa_pcm, hwparams, &rate, 0);
874 debug_printf(" snd_pcm_hw_params_set_rate_near(alsa_pcm, hwparams, &rate = %i, 0) = %s\n", rate, snd_strerror(-err));
875 if (err<0)
876 {
877 fprintf(stderr, "ALSA: snd_pcm_hw_params_set_rate_near() failed: %s\n", snd_strerror(-err));
878 return;
879 }
880 if (rate==0)
881 {
882 fprintf(stderr, "ALSA: No usable samplerate available.\n");
883 return;
884 }
885
886 val = 500000;
887 err=snd_pcm_hw_params_set_buffer_time_near(alsa_pcm, hwparams, &val, 0);
888 debug_printf(" snd_pcm_hw_params_set_buffer_time_near(alsa_pcm, hwparams, 500000 uS => %d, 0) = %s\n", val, snd_strerror(-err));
889 if (err)
890 {
891 fprintf(stderr, "ALSA: snd_pcm_hw_params_set_buffer_time_near() failed: %s\n", snd_strerror(-err));
892 return;
893 }
894
895 err=snd_pcm_hw_params(alsa_pcm, hwparams);
896 debug_printf(" snd_pcm_hw_params(alsa_pcm, hwparams) = %s\n", snd_strerror(-err));
897 if (err<0)
898 {
899 fprintf(stderr, "ALSA: snd_pcm_hw_params() failed: %s\n", snd_strerror(-err));
900 return;
901 }
902
903 err=snd_pcm_sw_params_current(alsa_pcm, swparams);
904 debug_printf(" snd_pcm_sw_params_current(alsa_pcm, swparams) = %s\n", snd_strerror(-err));
905 if (err<0)
906 {
907 fprintf(stderr, "ALSA: snd_pcm_sw_params_any() failed: %s\n", snd_strerror(-err));
908 return;
909 }
910
911 err=snd_pcm_sw_params(alsa_pcm, swparams);
912 debug_printf(" snd_pcm_sw_params(alsa_pcm, swparams) = %s\n", snd_strerror(-err));
913 if (err<0)
914 {
915 fprintf(stderr, "ALSA: snd_pcm_sw_params() failed: %s\n", snd_strerror(-err));
916 return;
917 }
918 plrRate=rate;
919 plrOpt=opt;
920 }
921
922 #ifdef PLR_DEBUG
alsaDebug(void)923 static char *alsaDebug(void)
924 {
925 static char buffer[100];
926 strcpy(buffer, "devpalsa: ");
927 convnum(cachelen, buffer+9, 10, 5, 1);
928 strcat(buffer, "/");
929 convnum(kernlen, buffer+15, 10, 5, 1);
930 strcat(buffer, "/");
931 convnum(buflen, buffer+21, 10, 5, 1);
932 return buffer;
933 }
934 #endif
935
alsaPlay(void ** buf,unsigned int * len,struct ocpfilehandle_t * source_file)936 static int alsaPlay(void **buf, unsigned int *len, struct ocpfilehandle_t *source_file)
937 {
938 if (!alsa_pcm)
939 return 0;
940
941 if ((*len)<(plrRate&~3))
942 *len=plrRate&~3;
943 if ((*len)>(plrRate*4))
944 *len=plrRate*4;
945 playbuf=*buf=malloc(*len);
946
947 memsetd(*buf, (plrOpt&PLR_SIGNEDOUT)?0:(plrOpt&PLR_16BIT)?0x80008000:0x80808080, (*len)>>2);
948
949 buflen=*len;
950 bufpos=0;
951 cachepos=0;
952 cachelen=0;
953 playpos=0;
954 kernpos=0;
955 kernlen=0;
956
957 plrGetBufPos=getbufpos;
958 plrGetPlayPos=getplaypos;
959 plrIdle=flush;
960 plrAdvanceTo=advance;
961 plrGetTimer=gettimer;
962 #ifdef PLR_DEBUG
963 plrDebug=alsaDebug;
964 #endif
965
966 #ifdef ALSA_DEBUG_OUTPUT
967 debug_output = open ("test-alsa.raw", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
968 #endif
969
970 return 1;
971 }
972
alsaStop(void)973 static void alsaStop(void)
974 {
975 #ifdef PLR_DEBUG
976 plrDebug=0;
977 #endif
978 free(playbuf);
979
980 #ifdef ALSA_DEBUG_OUTPUT
981 close (debug_output);
982 debug_output = -1;
983 #endif
984
985 }
986
987 /* plr API stop */
988
989
990 /* driver front API start */
991
alsaOpenDevice(void)992 static void alsaOpenDevice(void)
993 {
994 int err;
995 snd_mixer_elem_t *current;
996
997 alsa_mixers_n=0;
998
999 /* if any device already open, please close it */
1000 debug_printf ("alsaOpenDevice()\n");
1001 if (alsa_pcm)
1002 {
1003 err=snd_pcm_drain(alsa_pcm);
1004 debug_printf(" snd_pcm_drain(alsa_pcm) = %s\n", snd_strerror(-err));
1005
1006 err=snd_pcm_close(alsa_pcm);
1007 debug_printf(" snd_pcm_close(alsa_pcm) = %s\n", snd_strerror(-err));
1008 alsa_pcm=NULL;
1009 }
1010
1011 if (mixer)
1012 {
1013 err=snd_mixer_close(mixer);
1014 debug_printf(" snd_mixer_close(mixer) = %s\n", snd_strerror(-err));
1015 mixer=NULL;
1016 }
1017
1018 /* open PCM device */
1019 err=snd_pcm_open(&alsa_pcm, alsaCardName, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
1020 debug_printf(" snd_pcm_open(&alsa_pcm, device = \"%s\", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) = %s\n", alsaCardName, snd_strerror(-err));
1021 if (err<0)
1022 {
1023 fprintf(stderr, "ALSA: failed to open pcm device (%s): %s\n", alsaCardName, snd_strerror(-err));
1024 alsa_pcm=NULL;
1025 return;
1026 }
1027
1028 /* Any mixer to open ? */
1029 if (!strlen(alsaMixerName))
1030 return;
1031
1032 err=snd_mixer_open(&mixer, 0);
1033 debug_printf(" snd_mixer_open(&mixer, 0) = %s\n", snd_strerror(-err));
1034 if (err<0)
1035 {
1036 fprintf(stderr, "ALSA: snd_mixer_open() failed: %s\n", snd_strerror(-err));
1037 return;
1038 }
1039
1040 err=snd_mixer_attach(mixer, alsaMixerName);
1041 debug_printf(" snd_mixer_attach(mixer, device = \"%s\") = %s\n", alsaMixerName, snd_strerror(-err));
1042 if (err<0)
1043 {
1044 fprintf(stderr, "ALSA: snd_mixer_attach() failed: %s\n", snd_strerror(-err));
1045 err=snd_mixer_close(mixer);
1046 debug_printf(" snd_mixer_close(mixer) = %s\n", snd_strerror(-err));
1047 mixer=NULL;
1048 return;
1049 }
1050
1051 err=snd_mixer_selem_register(mixer, NULL, NULL);
1052 debug_printf(" snd_mixer_selem_register(mixer, NULL, NULL) = %s\n", snd_strerror(-err));
1053 if (err<0)
1054 {
1055 fprintf(stderr, "ALSA: snd_mixer_selem_register() failed: %s\n", snd_strerror(-err));
1056
1057 err=snd_mixer_close(mixer);
1058 debug_printf(" snd_mixer_close(mixer) = %s\n", snd_strerror(-err));
1059 mixer=NULL;
1060 return;
1061 }
1062
1063 err=snd_mixer_load(mixer);
1064 debug_printf(" snd_mixer_load(mixer) = %s\n", snd_strerror(-err));
1065 if (err<0)
1066 {
1067 fprintf(stderr, "ALSA: snd_mixer_load() failed: %s\n", snd_strerror(-err));
1068
1069 err=snd_mixer_close(mixer);
1070 debug_printf(" snd_mixer_close(mixer) = %s\n", snd_strerror(-err));
1071 mixer=NULL;
1072 return;
1073 }
1074
1075 current = snd_mixer_first_elem(mixer);
1076 debug_printf (" snd_mixer_first_elem(mixer) = %p\n", current);
1077 while (current)
1078 {
1079 debug_printf (" snd_mixer_selem_is_active(current) = %d\n", snd_mixer_selem_is_active(current));
1080 debug_printf (" snd_mixer_selem_has_playback_volume = %d\n", snd_mixer_selem_has_playback_volume(current));
1081 if (snd_mixer_selem_is_active(current) &&
1082 snd_mixer_selem_has_playback_volume(current) &&
1083 (alsa_mixers_n<MAX_ALSA_MIXER))
1084 {
1085 long int a, b;
1086 long int min, max;
1087 snd_mixer_selem_get_playback_volume(current, SND_MIXER_SCHN_FRONT_LEFT, &a);
1088 snd_mixer_selem_get_playback_volume(current, SND_MIXER_SCHN_FRONT_RIGHT, &b);
1089 mixer_entries[alsa_mixers_n].val=(a+b)>>1;
1090 snd_mixer_selem_get_playback_volume_range(current, &min, &max);
1091 mixer_entries[alsa_mixers_n].min=min;
1092 mixer_entries[alsa_mixers_n].max=max;
1093 mixer_entries[alsa_mixers_n].step=1;
1094 mixer_entries[alsa_mixers_n].log=0;
1095 mixer_entries[alsa_mixers_n].name=snd_mixer_selem_get_name(current);
1096
1097 debug_printf (" name=%s\n", mixer_entries[alsa_mixers_n].name);
1098 debug_printf (" SND_MIXER_SCHN_FRONT_LEFT = %ld\n", a);
1099 debug_printf (" SND_MIXER_SCHN_FRONT_RIGHT = %ld\n", b);
1100 debug_printf (" min=%ld max=%ld\n", min, max);
1101
1102 alsa_mixers_n++;
1103 }
1104 current = snd_mixer_elem_next(current);
1105 debug_printf (" snd_mixer_elem_next(current) = %p\n", current);
1106 }
1107 }
1108
volalsaGetNumVolume(void)1109 static int volalsaGetNumVolume(void)
1110 {
1111 return alsa_mixers_n;
1112 }
1113
volalsaGetVolume(struct ocpvolstruct * v,int n)1114 static int volalsaGetVolume(struct ocpvolstruct *v, int n)
1115 {
1116 if (n<alsa_mixers_n)
1117 {
1118 memcpy(v, &mixer_entries[n], sizeof(mixer_entries[n]));
1119 return 1;
1120 }
1121 return 0;
1122 }
1123
volalsaSetVolume(struct ocpvolstruct * v,int n)1124 static int volalsaSetVolume(struct ocpvolstruct *v, int n)
1125 {
1126 int count=0, err;
1127 snd_mixer_elem_t *current;
1128
1129 debug_printf ("volalsaSetVolume(v->val=%d n=%d)\n", v->val, n);
1130
1131 current = snd_mixer_first_elem(mixer);
1132 while (current)
1133 {
1134 if (snd_mixer_selem_is_active(current) &&
1135 snd_mixer_selem_has_playback_volume(current))
1136 {
1137 if (count==n)
1138 {
1139 err = snd_mixer_selem_set_playback_volume(current, SND_MIXER_SCHN_FRONT_LEFT, v->val);
1140 debug_printf (" snd_mixer_selem_set_playback_volume(current %s, SND_MIXER_SCHN_FRONT_LEFT, %d) = %s\n", snd_mixer_selem_get_name (current), v->val, snd_strerror(-err));
1141 err = snd_mixer_selem_set_playback_volume(current, SND_MIXER_SCHN_FRONT_RIGHT, v->val);
1142 debug_printf (" snd_mixer_selem_set_playback_volume(current %s, SND_MIXER_SCHN_FRONT_RIGHT, %d) = %s\n", snd_mixer_selem_get_name (current), v->val, snd_strerror(-err));
1143 mixer_entries[n].val=v->val;
1144 return 1;
1145 }
1146 count++;
1147 }
1148 current = snd_mixer_elem_next(current);
1149 }
1150 return 0;
1151 }
1152
alsaInit(const struct deviceinfo * c)1153 static int alsaInit(const struct deviceinfo *c)
1154 {
1155 ocpdir_t_fill (&dir_alsa,
1156 dir_alsa_ref,
1157 dir_alsa_unref,
1158 dmSetup->basedir,
1159 dir_alsa_readdir_start,
1160 0,
1161 dir_alsa_readdir_cancel,
1162 dir_alsa_readdir_iterate,
1163 dir_alsa_readdir_dir,
1164 dir_alsa_readdir_file,
1165 0,
1166 dirdbFindAndRef (dmSetup->basedir->dirdb_ref, "alsa", dirdb_use_dir),
1167 0, /* refcount, ALSA ignores this */
1168 0, /* is_archive */
1169 0 /* is_playlist */);
1170 filesystem_setup_register_dir (&dir_alsa);
1171
1172 plRegisterInterface (&alsaPCMoutIntr);
1173
1174 plrSetOptions=SetOptions;
1175 plrPlay=alsaPlay;
1176 plrStop=alsaStop;
1177
1178 alsaOpenDevice();
1179 if (!alsa_pcm)
1180 return 0;
1181
1182 SetOptions(44100, PLR_16BIT|PLR_STEREO);
1183 return 1;
1184 }
1185
alsaDetect(struct deviceinfo * card)1186 static int alsaDetect(struct deviceinfo *card)
1187 {
1188 int cards = detect_cards ();
1189
1190 card->devtype=&plrAlsa;
1191
1192 snprintf (card->path, sizeof(card->path), "%s", cfGetProfileString("devpALSA", "path", "default"));
1193 snprintf (alsaCardName, sizeof(alsaCardName), "%s", card->path);
1194
1195 snprintf (card->mixer, sizeof(card->mixer), "%s", cfGetProfileString("devpALSA", "mixer", "default"));
1196 snprintf (alsaMixerName, sizeof(alsaMixerName), "%s", card->mixer);
1197 /*
1198 card->irq = -1;
1199 card->irq2 = -1;
1200 card->dma = -1;
1201 card->dma2 = -1;
1202 */
1203 card->subtype = -1;
1204 card->mem = 0;
1205 card->chan = 2;
1206
1207 return cards > 0;
1208 }
1209
alsaClose(void)1210 static void alsaClose(void)
1211 {
1212 plrPlay=0;
1213
1214 plUnregisterInterface (&alsaPCMoutIntr);
1215
1216 filesystem_setup_unregister_dir (&dir_alsa);
1217 dirdbUnref (dir_alsa.dirdb_ref, dirdb_use_dir);
1218 }
1219
alsaMixerIntrSetDev(struct moduleinfostruct * info,struct ocpfilehandle_t * f)1220 static int alsaMixerIntrSetDev (struct moduleinfostruct *info, struct ocpfilehandle_t *f)
1221 {
1222 char *name;
1223
1224 dirdbGetName_internalstr (f->dirdb_ref, &name);
1225
1226 #warning we must add custom.dev in the file-list!!
1227 if (!strcmp(name, "custom.dev"))
1228 {
1229 int mlTop=mlDrawBox();
1230 char str[DEVICE_NAME_MAX+1];
1231 unsigned int curpos;
1232 unsigned int cmdlen;
1233 int insmode=1;
1234 unsigned int scrolled=0;
1235
1236 strcpy(str, alsaCardName);
1237
1238 displaystr(mlTop+1, 5, 0x0b, "Give me something to crunch!!", 29);
1239 displaystr(mlTop+3, 5, 0x0b, "-- Finish with enter, abort with escape --", 32);
1240
1241 curpos=strlen(str);
1242 cmdlen=strlen(str);
1243 setcurshape(1);
1244
1245 while (1)
1246 {
1247 uint16_t key;
1248 displaystr(mlTop+2, 5, 0x8f, str+scrolled, plScrWidth-10);
1249 setcur(mlTop+2, 5+curpos-scrolled);
1250
1251 while (!ekbhit())
1252 framelock();
1253 key=egetch();
1254
1255 if ((key>=0x20)&&(key<=0x7f))
1256 {
1257 if (insmode)
1258 {
1259 if ((cmdlen+1)<sizeof(str))
1260 {
1261 memmove(str+curpos+1, str+curpos, cmdlen-curpos+1);
1262 str[curpos++]=key;
1263 cmdlen++;
1264 }
1265 } else if (curpos==cmdlen)
1266 {
1267 if ((cmdlen+1)<(sizeof(str)))
1268 {
1269 str[curpos++]=key;
1270 str[curpos]=0;
1271 cmdlen++;
1272 }
1273 } else
1274 str[curpos++]=key;
1275 } else switch (key)
1276 {
1277 case KEY_ESC:
1278 setcurshape(0);
1279 return 0;
1280 case KEY_LEFT:
1281 if (curpos)
1282 curpos--;
1283 break;
1284 case KEY_RIGHT:
1285 if (curpos<cmdlen)
1286 curpos++;
1287 break;
1288 case KEY_HOME:
1289 curpos=0;
1290 break;
1291 case KEY_END:
1292 curpos=cmdlen;
1293 break;
1294 case KEY_INSERT:
1295 {
1296 insmode=!insmode;
1297 setcurshape(insmode?1:2);
1298 }
1299 break;
1300 case KEY_DELETE:
1301 if (curpos!=cmdlen)
1302 {
1303 memmove(str+curpos, str+curpos+1, cmdlen-curpos);
1304 cmdlen--;
1305 }
1306 break;
1307 case KEY_BACKSPACE:
1308 if (curpos)
1309 {
1310 memmove(str+curpos-1, str+curpos, cmdlen-curpos+1);
1311 curpos--;
1312 cmdlen--;
1313 }
1314 break;
1315 case _KEY_ENTER:
1316 strcpy(alsaCardName, str);
1317 setcurshape(0);
1318 goto out;
1319 }
1320 while ((curpos-scrolled)>=(plScrWidth-10))
1321 scrolled+=8;
1322 while (((signed)curpos-(signed)scrolled)<0)
1323 scrolled-=8;
1324 }
1325 }
1326 /* 1.0.14rc1 added support for snd_device_name_hint */
1327 else if (!strncmp(name, "alsa-", 4))
1328 {
1329 snprintf (alsaCardName, sizeof (alsaCardName), "%s", info->modname);
1330 snprintf (alsaMixerName, sizeof (alsaCardName), "%s", info->modname);
1331 }
1332 out:
1333 fprintf(stderr, "ALSA: Selected PCM %s\n", alsaCardName);
1334 fprintf(stderr, "ALSA: Selected Mixer %s\n", alsaMixerName);
1335
1336 if (custom_dsp_mdb_ref!=0xffffffff)
1337 {
1338 struct moduleinfostruct mi;
1339 mdbGetModuleInfo(&mi, custom_dsp_mdb_ref);
1340 snprintf(mi.modname, sizeof(mi.modname), "%s", alsaCardName);
1341 mdbWriteModuleInfo(custom_dsp_mdb_ref, &mi);
1342 }
1343 if (custom_mixer_mdb_ref!=0xffffffff)
1344 {
1345 struct moduleinfostruct mi;
1346 mdbGetModuleInfo(&mi, custom_mixer_mdb_ref);
1347 snprintf(mi.modname, sizeof(mi.modname), "%s", alsaMixerName);
1348 mdbWriteModuleInfo(custom_mixer_mdb_ref, &mi);
1349 }
1350
1351 return 0;
1352 }
1353
init(void)1354 static void __attribute__((constructor))init(void)
1355 {
1356 int err;
1357 if ((err = snd_pcm_status_malloc(&alsa_pcm_status)))
1358 {
1359 fprintf(stderr, "snd_pcm_status_malloc() failed, %s\n", snd_strerror(-err));
1360 exit(0);
1361 }
1362 if ((err = snd_pcm_hw_params_malloc(&hwparams)))
1363 {
1364 fprintf(stderr, "snd_pcm_hw_params_malloc failed, %s\n", snd_strerror(-err));
1365 exit(0);
1366 }
1367 if ((err = snd_pcm_sw_params_malloc(&swparams)))
1368 {
1369 fprintf(stderr, "snd_pcm_sw_params_malloc failed, %s\n", snd_strerror(-err));
1370 exit(0);
1371 }
1372 }
1373
fini(void)1374 static void __attribute__((destructor))fini(void)
1375 {
1376 int err;
1377
1378 debug_printf("ALSA_fini()\n");
1379
1380 if (alsa_pcm)
1381 {
1382 err=snd_pcm_drain(alsa_pcm);
1383 debug_printf(" snd_pcm_drain(alsa_pcm) = %s\n", snd_strerror(-err));
1384
1385 err=snd_pcm_close(alsa_pcm);
1386 debug_printf(" snd_pcm_close(alsa_pcm) = %s\n", snd_strerror(-err));
1387
1388 alsa_pcm=NULL;
1389 }
1390
1391 if (mixer)
1392 {
1393 err=snd_mixer_close(mixer);
1394 debug_printf(" snd_mixer_close(mixer) = %s\n", snd_strerror(-err));
1395 mixer=NULL;
1396 }
1397
1398 if (alsa_pcm_status)
1399 {
1400 snd_pcm_status_free(alsa_pcm_status);
1401 alsa_pcm_status = NULL;
1402 }
1403
1404 if (hwparams)
1405 {
1406 snd_pcm_hw_params_free(hwparams);
1407 hwparams=NULL;
1408 }
1409
1410 if (swparams)
1411 {
1412 snd_pcm_sw_params_free(swparams);
1413 swparams=NULL;
1414 }
1415
1416 snd_config_update_free_global ();
1417
1418 alsa_mixers_n=0;
1419 }
1420
1421 struct sounddevice plrAlsa={SS_PLAYER, 1, "ALSA device driver", alsaDetect, alsaInit, alsaClose, NULL};
1422 static struct interfacestruct alsaPCMoutIntr = {alsaMixerIntrSetDev, 0, 0, "alsaPCMoutIntr" INTERFACESTRUCT_TAIL};
1423 struct ocpvolregstruct volalsa={volalsaGetNumVolume, volalsaGetVolume, volalsaSetVolume};
1424
1425 char *dllinfo="driver plrAlsa; volregs volalsa";
1426 struct linkinfostruct dllextinfo = {.name = "devpalsa", .desc = "OpenCP Player Device: ALSA (c) 2005-21 Stian Skjelstad", .ver = DLLVERSION, .size = 0};
1427