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