1 /*
2 	audio: audio output interface
3 
4 	copyright ?-2020 by the mpg123 project - free software under the terms of the LGPL 2.1
5 	see COPYING and AUTHORS files in distribution or http://mpg123.org
6 	initially written by Michael Hipp
7 */
8 
9 #include "out123_int.h"
10 #include "wav.h"
11 #include "hextxt.h"
12 #ifndef NOXFERMEM
13 #include "buffer.h"
have_buffer(out123_handle * ao)14 static int have_buffer(out123_handle *ao)
15 {
16 	return (ao->buffer_pid != -1);
17 }
18 #endif
19 #include "stringlists.h"
20 
21 #include "debug.h"
22 
23 /* An output that is live and does not deal with pausing itself.
24    The device needs to be closed if we stop feeding. */
25 #define SENSITIVE_OUTPUT(ao) \
26   (    (ao)->propflags & OUT123_PROP_LIVE \
27   && !((ao)->propflags & OUT123_PROP_PERSISTENT) )
28 
29 static const char *default_name = "out123";
30 
modverbose(out123_handle * ao,int final)31 static int modverbose(out123_handle *ao, int final)
32 {
33 	mdebug( "modverbose: %x %x %x %d %d"
34 	,	(unsigned)ao->flags, (unsigned)ao->auxflags, (unsigned)OUT123_QUIET
35 	,	final, ao->verbose );
36 	return final ? (AOQUIET ? 0 : ao->verbose) : -1;
37 }
38 
39 static void check_output_module( out123_handle *ao
40 ,	const char *name, const char *device, int final );
41 
out123_clear_module(out123_handle * ao)42 static void out123_clear_module(out123_handle *ao)
43 {
44 	ao->open = NULL;
45 	ao->get_formats = NULL;
46 	ao->write = NULL;
47 	ao->flush = NULL;
48 	ao->drain = NULL;
49 	ao->close = NULL;
50 	ao->deinit = NULL;
51 	ao->enumerate = NULL;
52 
53 	ao->module = NULL;
54 	ao->userptr = NULL;
55 	ao->fn = -1;
56 	/* The default is live output devices, files are the special case. */
57 	ao->propflags = OUT123_PROP_LIVE;
58 }
59 
60 /* Ensure that real name is not leaked, needs to be freed before any call to
61    ao->open(ao). One might free it on closing already, but it might be sensible
62    to keep it around, might still be the same after re-opening. */
aoopen(out123_handle * ao)63 static int aoopen(out123_handle *ao)
64 {
65 	if(ao->realname)
66 	{
67 		free(ao->realname);
68 		ao->realname = NULL;
69 	}
70 	return ao->open(ao);
71 }
72 
out123_new(void)73 out123_handle* attribute_align_arg out123_new(void)
74 {
75 	out123_handle* ao = malloc( sizeof( out123_handle ) );
76 	if(!ao)
77 		return NULL;
78 	ao->errcode = 0;
79 #ifndef NOXFERMEM
80 	ao->buffer_pid = -1;
81 	ao->buffer_fd[0] = -1;
82 	ao->buffer_fd[1] = -1;
83 	ao->buffermem = NULL;
84 #endif
85 
86 	out123_clear_module(ao);
87 	ao->name = compat_strdup(default_name);
88 	ao->realname = NULL;
89 	ao->driver = NULL;
90 	ao->device = NULL;
91 
92 	ao->flags = OUT123_KEEP_PLAYING;
93 	ao->rate = -1;
94 	ao->gain = -1;
95 	ao->channels = -1;
96 	ao->format = -1;
97 	ao->framesize = 0;
98 	memset(ao->zerosample, 0, 8);
99 	ao->state = play_dead;
100 	ao->auxflags = 0;
101 	ao->preload = 0.;
102 	ao->verbose = 0;
103 	ao->device_buffer = 0.;
104 	ao->bindir = NULL;
105 	return ao;
106 }
107 
out123_del(out123_handle * ao)108 void attribute_align_arg out123_del(out123_handle *ao)
109 {
110 	debug2("[%ld]out123_del(%p)", (long)getpid(), (void*)ao);
111 	if(!ao) return;
112 
113 	out123_close(ao); /* TODO: That talks to the buffer if present. */
114 	out123_set_buffer(ao, 0);
115 #ifndef NOXFERMEM
116 	if(have_buffer(ao)) buffer_exit(ao);
117 #endif
118 	if(ao->name)
119 		free(ao->name);
120 	if(ao->bindir)
121 		free(ao->bindir);
122 	free(ao);
123 }
124 
out123_free(void * ptr)125 void attribute_align_arg out123_free(void *ptr)
126 {
127 	free(ptr);
128 }
129 
130 /* Error reporting */
131 
132 /* Carefully keep that in sync with the error enum! */
133 /* Sizing according to contents so that we can check! */
134 static const char *const errstring[] =
135 {
136 	"no problem"
137 ,	"out of memory"
138 ,	"bad driver name"
139 ,	"failure loading driver module"
140 ,	"no driver loaded"
141 ,	"no active audio device"
142 ,	"some device playback error"
143 ,	"failed to open device"
144 ,	"buffer (communication) error"
145 ,	"basic module system error"
146 ,	"bad function argument(s)"
147 ,	"unknown parameter code"
148 ,	"attempt to set read-only parameter"
149 ,	"invalid out123 handle"
150 ,	"operation not supported"
151 ,	"device enumeration failed"
152 };
153 
out123_strerror(out123_handle * ao)154 const char* attribute_align_arg out123_strerror(out123_handle *ao)
155 {
156 	return out123_plain_strerror(out123_errcode(ao));
157 }
158 
out123_errcode(out123_handle * ao)159 int out123_errcode(out123_handle *ao)
160 {
161 	if(!ao) return OUT123_BAD_HANDLE;
162 	else    return ao->errcode;
163 }
164 
out123_plain_strerror(int errcode)165 const char* attribute_align_arg out123_plain_strerror(int errcode)
166 {
167 	if(errcode == OUT123_ERR)
168 		return "some generic error";
169 	if(errcode >= OUT123_ERRCOUNT || errcode < 0)
170 		return "invalid error code";
171 
172 	/* Let's be paranoid, one _may_ forget to extend errstrings when
173 	   adding a new entry to the enum. */
174 	if(errcode >= sizeof(errstring)/sizeof(char*))
175 		return "outdated error list (library bug)";
176 
177 	return errstring[errcode];
178 }
179 
out123_seterr(out123_handle * ao,enum out123_error errcode)180 static int out123_seterr(out123_handle *ao, enum out123_error errcode)
181 {
182 	if(!ao)
183 		return OUT123_ERR;
184 	ao->errcode = errcode;
185 	return errcode == OUT123_OK ? OUT123_OK : OUT123_ERR;
186 }
187 
188 /* pre-playback setup */
189 
190 int attribute_align_arg
out123_set_buffer(out123_handle * ao,size_t buffer_bytes)191 out123_set_buffer(out123_handle *ao, size_t buffer_bytes)
192 {
193 	debug2("out123_set_buffer(%p, %"SIZE_P")", (void*)ao, (size_p)buffer_bytes);
194 	if(!ao)
195 		return OUT123_ERR;
196 	ao->errcode = 0;
197 	/* Close any audio output module if present, also kill of buffer if present,
198 	   then start new buffer process with newly allocated storage if given
199 	   size is non-zero. */
200 	out123_close(ao);
201 #ifndef NOXFERMEM
202 	if(have_buffer(ao))
203 		buffer_exit(ao);
204 	if(buffer_bytes)
205 		return buffer_init(ao, buffer_bytes);
206 #endif
207 	return 0;
208 }
209 
210 int attribute_align_arg
out123_param2(out123_handle * ao,int code,long value,double fvalue,const char * svalue)211 out123_param2( out123_handle *ao, int code
212             , long value, double fvalue, const char *svalue )
213 {
214 	return out123_param(ao, code, value, fvalue, svalue);
215 }
216 
217 int attribute_align_arg
out123_param(out123_handle * ao,enum out123_parms code,long value,double fvalue,const char * svalue)218 out123_param( out123_handle *ao, enum out123_parms code
219             , long value, double fvalue, const char *svalue )
220 {
221 	int ret = 0;
222 
223 	debug4("out123_param(%p, %i, %li, %g)", (void*)ao, (int)code, value, fvalue);
224 	if(!ao)
225 		return OUT123_ERR;
226 	ao->errcode = 0;
227 
228 	switch(code)
229 	{
230 		case OUT123_FLAGS:
231 			ao->flags = (int)value;
232 		break;
233 		case OUT123_ADD_FLAGS:
234 			ao->flags |= (int)value;
235 		break;
236 		case OUT123_REMOVE_FLAGS:
237 			ao->flags &= ~((int)value);
238 		break;
239 		case OUT123_PRELOAD:
240 			ao->preload = fvalue;
241 		break;
242 		case OUT123_GAIN:
243 			ao->gain = value;
244 		break;
245 		case OUT123_VERBOSE:
246 			ao->verbose = (int)value;
247 		break;
248 		case OUT123_DEVICEBUFFER:
249 			ao->device_buffer = fvalue;
250 		break;
251 		case OUT123_PROPFLAGS:
252 			ao->errcode = OUT123_SET_RO_PARAM;
253 			ret = OUT123_ERR;
254 		break;
255 		case OUT123_NAME:
256 			if(ao->name)
257 				free(ao->name);
258 			ao->name = compat_strdup(svalue ? svalue : default_name);
259 		break;
260 		case OUT123_BINDIR:
261 			if(ao->bindir)
262 				free(ao->bindir);
263 			ao->bindir = compat_strdup(svalue);
264 		break;
265 		default:
266 			ao->errcode = OUT123_BAD_PARAM;
267 			if(!AOQUIET) error1("bad parameter code %i", (int)code);
268 			ret = OUT123_ERR;
269 	}
270 #ifndef NOXFERMEM
271 	/* If there is a buffer, it needs to update its copy of parameters. */
272 	if(have_buffer(ao))
273 		/* No error check; if that fails, buffer is dead and we will notice
274 		   soon enough. */
275 		buffer_sync_param(ao);
276 #endif
277 	return ret;
278 }
279 
280 int attribute_align_arg
out123_getparam2(out123_handle * ao,int code,long * ret_value,double * ret_fvalue,char ** ret_svalue)281 out123_getparam2( out123_handle *ao, int code
282                , long *ret_value, double *ret_fvalue, char* *ret_svalue )
283 {
284 	return out123_getparam(ao, code, ret_value, ret_fvalue, ret_svalue);
285 }
286 
287 int attribute_align_arg
out123_getparam(out123_handle * ao,enum out123_parms code,long * ret_value,double * ret_fvalue,char ** ret_svalue)288 out123_getparam( out123_handle *ao, enum out123_parms code
289                , long *ret_value, double *ret_fvalue, char* *ret_svalue )
290 {
291 	int ret = 0;
292 	long value = 0;
293 	double fvalue = 0.;
294 	char *svalue = NULL;
295 
296 	debug4( "out123_getparam(%p, %i, %p, %p)"
297 	,	(void*)ao, (int)code, (void*)ret_value, (void*)ret_fvalue );
298 	if(!ao)
299 		return OUT123_ERR;
300 	ao->errcode = 0;
301 
302 	switch(code)
303 	{
304 		case OUT123_FLAGS:
305 		case OUT123_ADD_FLAGS:
306 			value = ao->flags;
307 		break;
308 		case OUT123_PRELOAD:
309 			fvalue = ao->preload;
310 		break;
311 		case OUT123_GAIN:
312 			value = ao->gain;
313 		break;
314 		case OUT123_VERBOSE:
315 			value = ao->verbose;
316 		break;
317 		case OUT123_DEVICEBUFFER:
318 			fvalue = ao->device_buffer;
319 		break;
320 		case OUT123_PROPFLAGS:
321 			value = ao->propflags;
322 		break;
323 		case OUT123_NAME:
324 			svalue = ao->realname ? ao->realname : ao->name;
325 		break;
326 		case OUT123_BINDIR:
327 			svalue = ao->bindir;
328 		break;
329 		default:
330 			if(!AOQUIET) error1("bad parameter code %i", (int)code);
331 			ao->errcode = OUT123_BAD_PARAM;
332 			ret = OUT123_ERR;
333 	}
334 	if(!ret)
335 	{
336 		if(ret_value)  *ret_value  = value;
337 		if(ret_fvalue) *ret_fvalue = fvalue;
338 		if(ret_svalue) *ret_svalue = svalue;
339 	}
340 	return ret;
341 }
342 
343 int attribute_align_arg
out123_param_from(out123_handle * ao,out123_handle * from_ao)344 out123_param_from(out123_handle *ao, out123_handle* from_ao)
345 {
346 	debug2("out123_param_from(%p, %p)", (void*)ao, (void*)from_ao);
347 	if(!ao || !from_ao) return -1;
348 
349 	ao->flags     = from_ao->flags;
350 	ao->preload   = from_ao->preload;
351 	ao->gain      = from_ao->gain;
352 	ao->device_buffer = from_ao->device_buffer;
353 	ao->verbose   = from_ao->verbose;
354 	if(ao->name)
355 		free(ao->name);
356 	ao->name = compat_strdup(from_ao->name);
357 	if(ao->bindir)
358 		free(ao->bindir);
359 	ao->bindir = compat_strdup(from_ao->bindir);
360 
361 	return 0;
362 }
363 
364 #ifndef NOXFERMEM
365 /* Serialization of tunable parameters to communicate them between
366    main process and buffer. Make sure these two stay in sync ... */
367 
write_parameters(out123_handle * ao,int who)368 int write_parameters(out123_handle *ao, int who)
369 {
370 	int fd = ao->buffermem->fd[who];
371 	if(
372 		GOOD_WRITEVAL(fd, ao->flags)
373 	&&	GOOD_WRITEVAL(fd, ao->preload)
374 	&&	GOOD_WRITEVAL(fd, ao->gain)
375 	&&	GOOD_WRITEVAL(fd, ao->device_buffer)
376 	&&	GOOD_WRITEVAL(fd, ao->verbose)
377 	&& !xfer_write_string(ao, who, ao->name)
378 	&& !xfer_write_string(ao, who, ao->bindir)
379 	)
380 		return 0;
381 	else
382 		return -1;
383 }
384 
read_parameters(out123_handle * ao,int who,byte * prebuf,int * preoff,int presize)385 int read_parameters(out123_handle *ao
386 ,	int who, byte *prebuf, int *preoff, int presize)
387 {
388 	int fd = ao->buffermem->fd[who];
389 #define GOOD_READVAL_BUF(fd, val) \
390 	!read_buf(fd, &val, sizeof(val), prebuf, preoff, presize)
391 	if(
392 		GOOD_READVAL_BUF(fd, ao->flags)
393 	&&	GOOD_READVAL_BUF(fd, ao->preload)
394 	&&	GOOD_READVAL_BUF(fd, ao->gain)
395 	&&	GOOD_READVAL_BUF(fd, ao->device_buffer)
396 	&&	GOOD_READVAL_BUF(fd, ao->verbose)
397 	&& !xfer_read_string(ao, who, &ao->name)
398 	&& !xfer_read_string(ao, who, &ao->bindir)
399 	)
400 		return 0;
401 	else
402 		return -1;
403 #undef GOOD_READVAL_BUF
404 }
405 #endif
406 
407 int attribute_align_arg
out123_open(out123_handle * ao,const char * driver,const char * device)408 out123_open(out123_handle *ao, const char* driver, const char* device)
409 {
410 	debug4( "[%ld]out123_open(%p, %s, %s)", (long)getpid(), (void*)ao
411 	,	driver ? driver : "<nil>", device ? device : "<nil>" );
412 	if(!ao)
413 		return OUT123_ERR;
414 	ao->errcode = 0;
415 
416 	out123_close(ao);
417 	debug("out123_open() continuing");
418 
419 	/* Ensure that audio format is freshly set for "no format yet" mode.
420 	   In out123_start*/
421 	ao->rate = -1;
422 	ao->channels = -1;
423 	ao->format = -1;
424 
425 #ifndef NOXFERMEM
426 	if(have_buffer(ao))
427 	{
428 		if(buffer_open(ao, driver, device))
429 			return OUT123_ERR;
430 	}
431 	else
432 #endif
433 	{
434 		/* We just quickly check if the device can be accessed at all,
435 		   same as out123_encodings! */
436 		char *nextname, *modnames;
437 		const char *names = driver ? driver : DEFAULT_OUTPUT_MODULE;
438 
439 		if(!names) return out123_seterr(ao, OUT123_BAD_DRIVER_NAME);
440 
441 		/* It is ridiculous how these error messages are larger than the pieces
442 		   of memory they are about! */
443 		if(device && !(ao->device = compat_strdup(device)))
444 		{
445 			if(!AOQUIET) error("OOM device name copy");
446 			return out123_seterr(ao, OUT123_DOOM);
447 		}
448 
449 		if(!(modnames = compat_strdup(names)))
450 		{
451 			out123_close(ao); /* Frees ao->device, too. */
452 			if(!AOQUIET) error("OOM driver names");
453 			return out123_seterr(ao, OUT123_DOOM);
454 		}
455 
456 		/* Now loop over the list of possible modules to find one that works. */
457 		nextname = strtok(modnames, ",");
458 		while(!ao->open && nextname)
459 		{
460 			char *curname = nextname;
461 			nextname = strtok(NULL, ",");
462 			check_output_module(ao, curname, device, !nextname);
463 			if(ao->open)
464 			{
465 				if(AOVERBOSE(2))
466 					fprintf(stderr, "Chosen output module: %s\n", curname);
467 				/* A bit redundant, but useful when it's a fake module. */
468 				if(!(ao->driver = compat_strdup(curname)))
469 				{
470 					out123_close(ao);
471 					if(!AOQUIET) error("OOM driver name");
472 					return out123_seterr(ao, OUT123_DOOM);
473 				}
474 			}
475 		}
476 
477 		free(modnames);
478 
479 		if(!ao->open) /* At least an open() routine must be present. */
480 		{
481 			if(!AOQUIET)
482 				error2("Found no driver out of [%s] working with device %s."
483 				,	names, device ? device : "<default>");
484 			/* Proper more detailed error code could be set already. */
485 			if(ao->errcode == OUT123_OK)
486 				ao->errcode = OUT123_BAD_DRIVER;
487 			return OUT123_ERR;
488 		}
489 	}
490 	/* Got something. */
491 	ao->state = play_stopped;
492 	return OUT123_OK;
493 }
494 
495 /* Be resilient, always do cleanup work regardless of state. */
out123_close(out123_handle * ao)496 void attribute_align_arg out123_close(out123_handle *ao)
497 {
498 	debug2("[%ld]out123_close(%p)", (long)getpid(), (void*)ao);
499 	if(!ao)
500 		return;
501 	ao->errcode = 0;
502 
503 	out123_drain(ao);
504 	out123_stop(ao);
505 
506 #ifndef NOXFERMEM
507 	if(have_buffer(ao))
508 		buffer_close(ao);
509 	else
510 #endif
511 	{
512 		if(ao->deinit)
513 			ao->deinit(ao);
514 		if(ao->module)
515 			close_module(ao->module, modverbose(ao, 0));
516 		/* Null module methods and pointer. */
517 		out123_clear_module(ao);
518 	}
519 
520 	/* These copies exist in addition to the ones for the buffer. */
521 	if(ao->driver)
522 		free(ao->driver);
523 	ao->driver = NULL;
524 	if(ao->device)
525 		free(ao->device);
526 	ao->device = NULL;
527 	if(ao->realname)
528 		free(ao->realname);
529 	ao->realname = NULL;
530 
531 	ao->state = play_dead;
532 }
533 
534 int attribute_align_arg
out123_start(out123_handle * ao,long rate,int channels,int encoding)535 out123_start(out123_handle *ao, long rate, int channels, int encoding)
536 {
537 	debug5( "[%ld]out123_start(%p, %li, %i, %i)", (long)getpid()
538 	,	(void*)ao, rate, channels, encoding );
539 	if(!ao)
540 		return OUT123_ERR;
541 	ao->errcode = 0;
542 
543 	out123_stop(ao);
544 	debug("out123_start() continuing");
545 	if(ao->state != play_stopped)
546 		return out123_seterr(ao, OUT123_NO_DRIVER);
547 
548 	/* Stored right away as parameters for ao->open() and also for reference.
549 	   framesize needed for out123_play(). */
550 	ao->rate      = rate;
551 	ao->channels  = channels;
552 	ao->format    = encoding;
553 	int samplesize = out123_encsize(encoding);
554 	ao->framesize = samplesize*channels;
555 	// The most convoluted way to say nothing at all.
556 	for(int i=0; i<samplesize; ++i)
557 #ifdef WORDS_BIGENDIAN
558 		ao->zerosample[samplesize-1-i] =
559 #else
560 		ao->zerosample[i] =
561 #endif
562 		MPG123_ZEROSAMPLE(ao->format, samplesize, i);
563 
564 #ifndef NOXFERMEM
565 	if(have_buffer(ao))
566 	{
567 		if(!buffer_start(ao))
568 		{
569 			ao->state = play_live;
570 			return OUT123_OK;
571 		}
572 		else
573 			return OUT123_ERR;
574 	}
575 	else
576 #endif
577 	{
578 		if(aoopen(ao) < 0)
579 			return out123_seterr(ao, OUT123_DEV_OPEN);
580 		ao->state = play_live;
581 		return OUT123_OK;
582 	}
583 }
584 
out123_pause(out123_handle * ao)585 void attribute_align_arg out123_pause(out123_handle *ao)
586 {
587 	debug3( "[%ld]out123_pause(%p) %i", (long)getpid()
588 	,	(void*)ao, ao ? (int)ao->state : -1 );
589 	if(ao && ao->state == play_live)
590 	{
591 #ifndef NOXFERMEM
592 		if(have_buffer(ao)){ debug("pause with buffer"); buffer_pause(ao); }
593 		else
594 #endif
595 		{
596 debug1("pause without buffer, sensitive=%d", SENSITIVE_OUTPUT(ao));
597 			/* Close live devices to avoid underruns. */
598 			if( SENSITIVE_OUTPUT(ao)
599 			  && ao->close && ao->close(ao) && !AOQUIET )
600 				error("trouble closing device");
601 		}
602 		ao->state = play_paused;
603 	}
604 }
605 
out123_continue(out123_handle * ao)606 void attribute_align_arg out123_continue(out123_handle *ao)
607 {
608 	debug3( "[%ld]out123_continue(%p) %i", (long)getpid()
609 	,	(void*)ao, ao ? (int)ao->state : -1 );
610 	if(ao && ao->state == play_paused)
611 	{
612 #ifndef NOXFERMEM
613 		if(have_buffer(ao)) buffer_continue(ao);
614 		else
615 #endif
616 		/* Re-open live devices to avoid underruns. */
617 		if(SENSITIVE_OUTPUT(ao) && aoopen(ao) < 0)
618 		{
619 			/* Will be overwritten by following out123_play() ... */
620 			ao->errcode = OUT123_DEV_OPEN;
621 			if(!AOQUIET)
622 				error("failed re-opening of device after pause");
623 			return;
624 		}
625 		ao->state = play_live;
626 	}
627 }
628 
out123_stop(out123_handle * ao)629 void attribute_align_arg out123_stop(out123_handle *ao)
630 {
631 	debug2("[%ld]out123_stop(%p)", (long)getpid(), (void*)ao);
632 	if(!ao)
633 		return;
634 	ao->errcode = 0;
635 	if(!(ao->state == play_paused || ao->state == play_live))
636 		return;
637 #ifndef NOXFERMEM
638 	if(have_buffer(ao))
639 		buffer_stop(ao);
640 	else
641 #endif
642 	if(   ao->state == play_live
643 	  || (ao->state == play_paused && !SENSITIVE_OUTPUT(ao)) )
644 	{
645 		if(ao->close && ao->close(ao) && !AOQUIET)
646 			error("trouble closing device");
647 	}
648 	ao->state = play_stopped;
649 }
650 
651 // Replace the data in a given block of audio data with zeroes
652 // in the correct encoding.
mute_block(unsigned char * bytes,int count,unsigned char * zerosample,int samplesize)653 static void mute_block( unsigned char *bytes, int count
654 ,	unsigned char* zerosample, int samplesize )
655 {
656 	// The count is expected to be a multiple of samplesize,
657 	// this is just to ensure that the loop ends properly, should be noop.
658 	count -= count % samplesize;
659 	if(!count)
660 		return;
661 	// Initialize with one zero sample, then multiply that
662 	// to eventually cover the whole buffer.
663 	memcpy(bytes, zerosample, samplesize);
664 	int offset = samplesize;
665 	count     -= samplesize;
666 	while(count)
667 	{
668 		int block = offset > count ? count : offset;
669 		memcpy(bytes+offset, bytes, block);
670 		offset += block;
671 		count  -= block;
672 	}
673 }
674 
675 size_t attribute_align_arg
out123_play(out123_handle * ao,void * bytes,size_t count)676 out123_play(out123_handle *ao, void *bytes, size_t count)
677 {
678 	size_t sum = 0;
679 	int written;
680 
681 	debug5( "[%ld]out123_play(%p, %p, %"SIZE_P") (%i)", (long)getpid()
682 	,	(void*)ao, bytes, (size_p)count, ao ? (int)ao->state : -1 );
683 	if(!ao)
684 		return 0;
685 	ao->errcode = 0;
686 	/* If paused, automatically continue. Other states are an error. */
687 	if(ao->state != play_live)
688 	{
689 		if(ao->state == play_paused)
690 			out123_continue(ao);
691 		if(ao->state != play_live)
692 		{
693 			ao->errcode = OUT123_NOT_LIVE;
694 			return 0;
695 		}
696 	}
697 
698 	/* Ensure that we are writing whole PCM frames. */
699 	count -= count % ao->framesize;
700 	if(!count) return 0;
701 
702 #ifndef NOXFERMEM
703 	if(have_buffer(ao))
704 		return buffer_write(ao, bytes, count);
705 	else
706 #endif
707 	{
708 		// Write 16K in a piece as maximum, as I've seen random short
709 		// writes of big blocks with ALSA.
710 		int maxcount = 1<<14;
711 		maxcount -= maxcount % ao->framesize;
712 		if(maxcount < 1)
713 			maxcount = ao->framesize;
714 		if(ao->flags & OUT123_MUTE)
715 			mute_block( bytes, count, ao->zerosample
716 			,	MPG123_SAMPLESIZE(ao->format) );
717 		do /* Playback in a loop to be able to continue after interruptions. */
718 		{
719 			errno = 0;
720 			int block = count > maxcount ? maxcount : count;
721 			written = ao->write(ao, bytes, block);
722 			debug4( "written: %d errno: %i (%s), keep_on=%d"
723 			,	written, errno, strerror(errno)
724 			,	ao->flags & OUT123_KEEP_PLAYING );
725 			if(written > 0)
726 			{
727 				bytes  = (char*)bytes+written;
728 				sum   += written;
729 				count -= written;
730 			}
731 			if(written < block && errno != EINTR)
732 			{
733 				ao->errcode = OUT123_DEV_PLAY;
734 				if(!AOQUIET)
735 					merror( "Error in writing audio, wrote only %d of %d (%s?)!"
736 					,	written, block, strerror(errno) );
737 				/* This is a serious issue ending this playback round. */
738 				break;
739 			}
740 		} while(count && ao->flags & OUT123_KEEP_PLAYING);
741 	}
742 	debug3( "out123_play(%p, %p, ...) = %"SIZE_P
743 	,	(void*)ao, bytes, (size_p)sum );
744 	return sum;
745 }
746 
747 /* Drop means to flush it down. Quickly. */
out123_drop(out123_handle * ao)748 void attribute_align_arg out123_drop(out123_handle *ao)
749 {
750 	debug2("[%ld]out123_drop(%p)", (long)getpid(), (void*)ao);
751 	if(!ao)
752 		return;
753 	ao->errcode = 0;
754 #ifndef NOXFERMEM
755 	if(have_buffer(ao))
756 		buffer_drop(ao);
757 	else
758 #endif
759 	if(ao->state == play_live)
760 	{
761 		if(ao->propflags & OUT123_PROP_LIVE && ao->flush)
762 			ao->flush(ao);
763 	}
764 }
765 
out123_drain(out123_handle * ao)766 void attribute_align_arg out123_drain(out123_handle *ao)
767 {
768 	debug2("[%ld]out123_drain(%p) ", (long)getpid(), (void*)ao);
769 	if(!ao)
770 		return;
771 	ao->errcode = 0;
772 	/* If paused, automatically continue. */
773 	if(ao->state != play_live)
774 	{
775 		if(ao->state == play_paused)
776 			out123_continue(ao);
777 		if(ao->state != play_live)
778 			return;
779 	}
780 #ifndef NOXFERMEM
781 	if(have_buffer(ao))
782 		buffer_drain(ao);
783 	else
784 #endif
785 	{
786 		if(ao->drain)
787 			ao->drain(ao);
788 		out123_pause(ao);
789 	}
790 }
791 
out123_ndrain(out123_handle * ao,size_t bytes)792 void attribute_align_arg out123_ndrain(out123_handle *ao, size_t bytes)
793 {
794 	debug3("[%ld]out123_ndrain(%p, %"SIZE_P")", (long)getpid(), (void*)ao, (size_p)bytes);
795 	if(!ao)
796 		return;
797 	ao->errcode = 0;
798 	/* If paused, automatically continue. */
799 	if(ao->state != play_live)
800 	{
801 		if(ao->state == play_paused)
802 			out123_continue(ao);
803 		if(ao->state != play_live)
804 			return;
805 	}
806 #ifndef NOXFERMEM
807 	if(have_buffer(ao))
808 		buffer_ndrain(ao, bytes);
809 	else
810 #endif
811 	{
812 		if(ao->drain)
813 			ao->drain(ao);
814 		out123_pause(ao);
815 	}
816 }
817 
818 
819 /* A function that does nothing and returns nothing. */
builtin_nothing(out123_handle * ao)820 static void builtin_nothing(out123_handle *ao){}
test_open(out123_handle * ao)821 static int test_open(out123_handle *ao)
822 {
823 	debug("test_open");
824 	return OUT123_OK;
825 }
test_get_formats(out123_handle * ao)826 static int test_get_formats(out123_handle *ao)
827 {
828 	debug("test_get_formats");
829 	return MPG123_ENC_ANY;
830 }
test_write(out123_handle * ao,unsigned char * buf,int len)831 static int test_write(out123_handle *ao, unsigned char *buf, int len)
832 {
833 	debug2("test_write: %i B from %p", len, (void*)buf);
834 	return len;
835 }
test_flush(out123_handle * ao)836 static void test_flush(out123_handle *ao)
837 {
838 	debug("test_flush");
839 }
test_drain(out123_handle * ao)840 static void test_drain(out123_handle *ao)
841 {
842 	debug("test_drain");
843 }
test_close(out123_handle * ao)844 static int test_close(out123_handle *ao)
845 {
846 	debug("test_drain");
847 	return 0;
848 }
849 
850 /* Open one of our builtin driver modules. */
open_fake_module(out123_handle * ao,const char * driver)851 static int open_fake_module(out123_handle *ao, const char *driver)
852 {
853 	if(!strcmp("test", driver))
854 	{
855 		ao->propflags &= ~OUT123_PROP_LIVE;
856 		ao->open  = test_open;
857 		ao->get_formats = test_get_formats;
858 		ao->write = test_write;
859 		ao->flush = test_flush;
860 		ao->drain = test_drain;
861 		ao->close = test_close;
862 	}
863 	else
864 	if(!strcmp("raw", driver))
865 	{
866 		ao->propflags &= ~OUT123_PROP_LIVE;
867 		ao->open  = raw_open;
868 		ao->get_formats = raw_formats;
869 		ao->write = wav_write;
870 		ao->flush = builtin_nothing;
871 		ao->drain = wav_drain;
872 		ao->close = raw_close;
873 	}
874 	else
875 	if(!strcmp("wav", driver))
876 	{
877 		ao->propflags &= ~OUT123_PROP_LIVE;
878 		ao->open = wav_open;
879 		ao->get_formats = wav_formats;
880 		ao->write = wav_write;
881 		ao->flush = builtin_nothing;
882 		ao->drain = wav_drain;
883 		ao->close = wav_close;
884 	}
885 	else
886 	if(!strcmp("cdr", driver))
887 	{
888 		ao->propflags &= ~OUT123_PROP_LIVE;
889 		ao->open  = cdr_open;
890 		ao->get_formats = cdr_formats;
891 		ao->write = wav_write;
892 		ao->flush = builtin_nothing;
893 		ao->drain = wav_drain;
894 		ao->close = raw_close;
895 	}
896 	else
897 	if(!strcmp("au", driver))
898 	{
899 		ao->propflags &= ~OUT123_PROP_LIVE;
900 		ao->open  = au_open;
901 		ao->get_formats = au_formats;
902 		ao->write = wav_write;
903 		ao->flush = builtin_nothing;
904 		ao->drain = wav_drain;
905 		ao->close = au_close;
906 	}
907 	else
908 	if(!strcmp("hex", driver))
909 	{
910 		ao->propflags &= ~OUT123_PROP_LIVE;
911 		ao->open  = hex_open;
912 		ao->get_formats = hex_formats;
913 		ao->write = hex_write;
914 		ao->flush = builtin_nothing;
915 		ao->drain = hextxt_drain;
916 		ao->close = hextxt_close;
917 	}
918 	else
919 	if(!strcmp("txt", driver))
920 	{
921 		ao->propflags &= ~OUT123_PROP_LIVE;
922 		ao->open  = txt_open;
923 		ao->get_formats = txt_formats;
924 		ao->write = txt_write;
925 		ao->flush = builtin_nothing;
926 		ao->drain = hextxt_drain;
927 		ao->close = hextxt_close;
928 	}
929 	else return OUT123_ERR;
930 
931 	return OUT123_OK;
932 }
933 
934 /* Check if given output module is loadable and has a working device.
935    final flag triggers printing and storing of errors. */
check_output_module(out123_handle * ao,const char * name,const char * device,int final)936 static void check_output_module( out123_handle *ao
937 ,	const char *name, const char *device, int final )
938 {
939 	int result;
940 
941 	debug3("check_output_module %p %p %p", (void*)ao, (void*)device, (void*)ao->device);
942 	if(AOVERBOSE(1))
943 		fprintf( stderr, "Trying output module: %s, device: %s\n"
944 		,	name, ao->device ? ao->device : "<nil>" );
945 
946 	/* Use internal code. */
947 	if(open_fake_module(ao, name) == OUT123_OK)
948 		return;
949 
950 	/* Open the module, initial check for availability+libraries. */
951 	ao->module = open_module( "output", name, modverbose(ao, final), ao->bindir);
952 	if(!ao->module)
953 		return;
954 	/* Check if module supports output */
955 	if(!ao->module->init_output)
956 	{
957 		if(final && !AOQUIET)
958 			error1("Module '%s' does not support audio output.", name);
959 		goto check_output_module_cleanup;
960 	}
961 
962 	/* Should I do funny stuff with stderr file descriptor instead? */
963 	if(final)
964 	{
965 		if(AOVERBOSE(2))
966 			fprintf(stderr
967 			,	"Note: %s is the last output option... showing you any error messages now.\n"
968 			,	name);
969 	}
970 	else ao->auxflags |= OUT123_QUIET; /* Probing, so don't spill stderr with errors. */
971 	result = ao->module->init_output(ao);
972 	if(result == 0)
973 	{ /* Try to open the device. I'm only interested in actually working modules. */
974 		ao->format = -1;
975 		result = aoopen(ao);
976 		debug1("ao->open() = %i", result);
977 		if(result >= 0) /* Opening worked, close again. */
978 			ao->close(ao);
979 		else
980 		{
981 			if(!AOQUIET)
982 				merror("Module '%s' device open failed.", name);
983 			if(ao->deinit)
984 				ao->deinit(ao); /* Failed, ensure that cleanup after init_output() occurs. */
985 		}
986 	}
987 	else if(!AOQUIET)
988 		error2("Module '%s' init failed: %i", name, result);
989 
990 	ao->auxflags &= ~OUT123_QUIET;
991 
992 	if(result >= 0)
993 		return;
994 
995 check_output_module_cleanup:
996 	/* Only if module did not check out we get to clean up here. */
997 	close_module(ao->module, modverbose(ao, final));
998 	out123_clear_module(ao);
999 	return;
1000 }
1001 
1002 /*
1003 static void audio_output_dump(out123_handle *ao)
1004 {
1005 	fprintf(stderr, "ao->fn=%d\n", ao->fn);
1006 	fprintf(stderr, "ao->userptr=%p\n", ao->userptr);
1007 	fprintf(stderr, "ao->rate=%ld\n", ao->rate);
1008 	fprintf(stderr, "ao->gain=%ld\n", ao->gain);
1009 	fprintf(stderr, "ao->device='%s'\n", ao->device);
1010 	fprintf(stderr, "ao->channels=%d\n", ao->channels);
1011 	fprintf(stderr, "ao->format=%d\n", ao->format);
1012 }
1013 */
1014 
1015 int attribute_align_arg
out123_drivers(out123_handle * ao,char *** names,char *** descr)1016 out123_drivers(out123_handle *ao, char ***names, char ***descr)
1017 {
1018 	char **tmpnames;
1019 	char **tmpdescr;
1020 	int count;
1021 
1022 	if(!ao)
1023 		return -1;
1024 
1025 	debug3("out123_drivers(%p, %p, %p)", (void*)ao, (void*)names, (void*)descr);
1026 	/* Wrap the call to isolate the lower levels from the user not being
1027 	   interested in both lists. it's a bit wasteful, but the code looks
1028 	   ugly enough already down there. */
1029 	count = list_modules("output", &tmpnames, &tmpdescr, modverbose(ao, 0), ao->bindir);
1030 	debug1("list_modules()=%i", count);
1031 	if(count < 0)
1032 	{
1033 		if(!AOQUIET)
1034 			error("Dynamic module search failed.");
1035 		count = 0;
1036 	}
1037 
1038 	if(
1039 		stringlists_add( &tmpnames, &tmpdescr
1040 		,	"raw", "raw headerless stream (builtin)", &count )
1041 	||	stringlists_add( &tmpnames, &tmpdescr
1042 		,	"cdr", "compact disc digital audio stream (builtin)", &count )
1043 	||	stringlists_add( &tmpnames, &tmpdescr
1044 		,	"wav", "RIFF WAVE file (builtin)", &count )
1045 	||	stringlists_add( &tmpnames, &tmpdescr
1046 		,	"au", "Sun AU file (builtin)", &count )
1047 	||	stringlists_add( &tmpnames, &tmpdescr
1048 		,	"test", "output into the void (builtin)", &count )
1049 	||	stringlists_add( &tmpnames, &tmpdescr
1050 		,	"hex", "interleaved hex printout (builtin)", &count )
1051 	||	stringlists_add( &tmpnames, &tmpdescr
1052 		,	"txt", "plain text printout, a column per channel (builtin)", &count )
1053 	)
1054 		if(!AOQUIET)
1055 			error("OOM");
1056 
1057 	/* Return or free gathered lists of names or descriptions. */
1058 	if(names)
1059 	{
1060 		*names = tmpnames;
1061 		tmpnames = NULL;
1062 	}
1063 	if(descr)
1064 	{
1065 		*descr = tmpdescr;
1066 		tmpdescr = NULL;
1067 	}
1068 	out123_stringlists_free(tmpnames, tmpdescr, count);
1069 	return count;
1070 }
1071 
1072 struct devlist
1073 {
1074 	int count;
1075 	char **names;
1076 	char **descr;
1077 };
1078 
devlist_add(void * dll,const char * name,const char * descr)1079 static int devlist_add(void *dll, const char *name, const char *descr)
1080 {
1081 	struct devlist *dl = (struct devlist*)dll;
1082 	return dl
1083 	?	stringlists_add(&(dl->names), &(dl->descr), name, descr, &(dl->count))
1084 	:	-1;
1085 }
1086 
out123_devices(out123_handle * ao,const char * driver,char *** names,char *** descr,char ** active_driver)1087 int out123_devices( out123_handle *ao, const char *driver, char ***names, char ***descr
1088 ,	char **active_driver )
1089 {
1090 	int ret = 0;
1091 	struct devlist dl = {0, NULL, NULL};
1092 	char *realdrv = NULL;
1093 	debug("");
1094 	if(!ao)
1095 		return -1;
1096 #ifndef NOXFERMEM
1097 	if(have_buffer(ao))
1098 		return out123_seterr(ao, OUT123_NOT_SUPPORTED);
1099 #endif
1100 
1101 	ao->errcode = OUT123_OK;
1102 	// If the driver is a single word, not a list with commas.
1103 	// Then don't try to open drivers just to know which we are talking about.
1104 	if(driver && strchr(driver, ',') == NULL)
1105 		realdrv = compat_strdup(driver);
1106 	else
1107 	{
1108 		mdebug("need to find a driver from: %s", driver ? driver : DEFAULT_OUTPUT_MODULE);
1109 		if(out123_open(ao, driver, NULL) != OUT123_OK)
1110 			return out123_seterr(ao, OUT123_BAD_DRIVER);
1111 		mdebug("deduced driver: %s", ao->driver);
1112 		realdrv = compat_strdup(ao->driver);
1113 	}
1114 	if(realdrv == NULL)
1115 		return out123_seterr(ao, OUT123_DOOM);
1116 
1117 	out123_close(ao);
1118 
1119 	if(open_fake_module(ao, realdrv) != OUT123_OK)
1120 	{
1121 		ao->module = open_module( "output", realdrv
1122 		,	modverbose(ao, 0), ao->bindir );
1123 		/* Open the module, initial check for availability+libraries. */
1124 		if( !ao->module || !ao->module->init_output
1125 			|| ao->module->init_output(ao) )
1126 			ret = out123_seterr(ao, OUT123_BAD_DRIVER);
1127 	}
1128 
1129 	if(!ret && ao->enumerate)
1130 	{
1131 		if(!ao->enumerate(ao, devlist_add, &dl))
1132 		{
1133 			ret = dl.count;
1134 			if(names)
1135 			{
1136 				*names = dl.names;
1137 				dl.names = NULL;
1138 			}
1139 			if(descr)
1140 			{
1141 				*descr = dl.descr;
1142 				dl.descr = NULL;
1143 			}
1144 			if(active_driver)
1145 			{
1146 				*active_driver = realdrv;
1147 				realdrv = NULL;
1148 			}
1149 		} else
1150 			ret = out123_seterr(ao, OUT123_DEV_ENUMERATE);
1151 		out123_stringlists_free(dl.names, dl.descr, dl.count);
1152 		if(ao->deinit)
1153 			ao->deinit(ao);
1154 	} else if(!ret)
1155 		ret = out123_seterr(ao, OUT123_NOT_SUPPORTED);
1156 
1157 	free(realdrv);
1158 	if(ao->module)
1159 		close_module(ao->module, modverbose(ao, 0));
1160 	out123_clear_module(ao);
1161 	return ret;
1162 }
1163 
1164 /* We always have ao->driver and ao->device set, also with buffer.
1165    The latter can be positively NULL, though. */
1166 int attribute_align_arg
out123_driver_info(out123_handle * ao,char ** driver,char ** device)1167 out123_driver_info(out123_handle *ao, char **driver, char **device)
1168 {
1169 	debug3( "out123_driver_info(%p, %p, %p)"
1170 	,	(void*)ao, (void*)driver, (void*)device );
1171 	if(!ao)
1172 		return OUT123_ERR;
1173 	if(!ao->driver)
1174 		return out123_seterr(ao, OUT123_NO_DRIVER);
1175 
1176 	if(driver)
1177 		*driver = ao->driver;
1178 	if(device)
1179 		*device = ao->device;
1180 	return OUT123_OK;
1181 }
1182 
1183 int attribute_align_arg
out123_encodings(out123_handle * ao,long rate,int channels)1184 out123_encodings(out123_handle *ao, long rate, int channels)
1185 {
1186 	debug4( "[%ld]out123_encodings(%p, %li, %i)", (long)getpid()
1187 	,	(void*)ao, rate, channels );
1188 	if(!ao)
1189 		return OUT123_ERR;
1190 	ao->errcode = OUT123_OK;
1191 
1192 	out123_stop(ao); /* That brings the buffer into waiting state, too. */
1193 
1194 	if(ao->state != play_stopped)
1195 		return out123_seterr(ao, OUT123_NO_DRIVER);
1196 
1197 	ao->channels = channels;
1198 	ao->rate     = rate;
1199 #ifndef NOXFERMEM
1200 	if(have_buffer(ao))
1201 		return buffer_encodings(ao);
1202 	else
1203 #endif
1204 	{
1205 		int enc = 0;
1206 		/* This tells outputs to choose a fitting format so that ao->open() succeeds
1207 		   They possibly set a sample rate and channel count they like best.
1208 		   We should add API to retrieve those defaults, too. */
1209 		ao->format   = -1;
1210 		if(aoopen(ao) >= 0)
1211 		{
1212 			/* Need to reset those since the choose-your-format open
1213 			   call might have changed them. */
1214 			ao->channels = channels;
1215 			ao->rate     = rate;
1216 			enc = ao->get_formats(ao);
1217 			ao->close(ao);
1218 			return enc;
1219 		}
1220 		else
1221 			return out123_seterr(ao, (ao->errcode != OUT123_OK
1222 			?	ao->errcode
1223 			:	OUT123_DEV_OPEN));
1224 	}
1225 }
1226 
out123_encsize(int encoding)1227 int attribute_align_arg out123_encsize(int encoding)
1228 {
1229 	return MPG123_SAMPLESIZE(encoding);
1230 }
1231 
1232 int attribute_align_arg
out123_formats(out123_handle * ao,const long * rates,int ratecount,int minchannels,int maxchannels,struct mpg123_fmt ** fmtlist)1233 out123_formats( out123_handle *ao, const long *rates, int ratecount
1234               , int minchannels, int maxchannels
1235               , struct mpg123_fmt **fmtlist )
1236 {
1237 	debug7( "[%ld]out123_formats(%p, %p, %i, %i, %i, %p)", (long)getpid()
1238 	,	(void*)ao, (void*)rates, ratecount, minchannels, maxchannels
1239 	,	(void*)fmtlist );
1240 	if(!ao)
1241 		return OUT123_ERR;
1242 	ao->errcode = OUT123_OK;
1243 
1244 	out123_stop(ao); /* That brings the buffer into waiting state, too. */
1245 
1246 	if(ao->state != play_stopped)
1247 		return out123_seterr(ao, OUT123_NO_DRIVER);
1248 
1249 	if(ratecount > 0 && !rates)
1250 		return out123_seterr(ao, OUT123_ARG_ERROR);
1251 	if(!fmtlist || minchannels > maxchannels)
1252 		return out123_seterr(ao, OUT123_ARG_ERROR);
1253 	*fmtlist = NULL; /* Initialize so free(fmtlist) is always allowed. */
1254 
1255 #ifndef NOXFERMEM
1256 	if(have_buffer(ao))
1257 		return buffer_formats( ao, rates, ratecount
1258 		                     , minchannels, maxchannels, fmtlist );
1259 	else
1260 #endif
1261 	{
1262 		/* This tells outputs to choose a fitting format so that ao->open()
1263 		   succeeds. */
1264 		ao->format   = -1;
1265 		ao->rate     = -1;
1266 		ao->channels = -1;
1267 		if(aoopen(ao) >= 0)
1268 		{
1269 			struct mpg123_fmt *fmts;
1270 			int ri, ch;
1271 			int fi = 0;
1272 			int fmtcount = 1; /* Always the default format. */
1273 			if(ratecount > 0)
1274 				fmtcount += ratecount*(maxchannels-minchannels+1);
1275 			if(!(fmts = malloc(sizeof(*fmts)*fmtcount)))
1276 			{
1277 				ao->close(ao);
1278 				return out123_seterr(ao, OUT123_DOOM);
1279 			}
1280 			/* Store default format if present. */
1281 			if(ao->format > 0 && ao->channels > 0 && ao->rate > 0)
1282 			{
1283 				fmts[0].rate     = ao->rate;
1284 				fmts[0].channels = ao->channels;
1285 				fmts[0].encoding = ao->format;
1286 			}
1287 			else
1288 			{ /* Ensure consistent -1 in all entries. */
1289 				fmts[0].rate     = -1;
1290 				fmts[0].channels = -1;
1291 				fmts[0].encoding = -1;
1292 			}
1293 			/* Test all combinations of rate and channel count. */
1294 			for(ri=0; ri<ratecount; ++ri)
1295 			for(ch=minchannels; ch<=maxchannels; ++ch)
1296 			{
1297 				++fi;
1298 				ao->rate = rates[ri];
1299 				ao->channels = ch;
1300 				fmts[fi].rate     = ao->rate;
1301 				fmts[fi].channels = ao->channels;
1302 				fmts[fi].encoding = ao->get_formats(ao);
1303 			}
1304 			ao->close(ao);
1305 
1306 			*fmtlist = fmts;
1307 			return fmtcount;
1308 		}
1309 		else
1310 			return out123_seterr(ao, (ao->errcode != OUT123_OK
1311 			?	ao->errcode
1312 			:	OUT123_DEV_OPEN));
1313 	}
1314 }
1315 
1316 
out123_buffered(out123_handle * ao)1317 size_t attribute_align_arg out123_buffered(out123_handle *ao)
1318 {
1319 	debug2("[%ld]out123_buffered(%p)", (long)getpid(), (void*)ao);
1320 	if(!ao)
1321 		return 0;
1322 	ao->errcode = 0;
1323 #ifndef NOXFERMEM
1324 	if(have_buffer(ao))
1325 	{
1326 		size_t fill = buffer_fill(ao);
1327 		debug2("out123_buffered(%p) = %"SIZE_P, (void*)ao, (size_p)fill);
1328 		return fill;
1329 	}
1330 	else
1331 #endif
1332 		return 0;
1333 }
1334 
out123_getformat(out123_handle * ao,long * rate,int * channels,int * encoding,int * framesize)1335 int attribute_align_arg out123_getformat( out123_handle *ao
1336 ,	long *rate, int *channels, int *encoding, int *framesize )
1337 {
1338 	if(!ao)
1339 		return OUT123_ERR;
1340 
1341 	if(!(ao->state == play_paused || ao->state == play_live))
1342 		return out123_seterr(ao, OUT123_NOT_LIVE);
1343 
1344 	if(rate)
1345 		*rate = ao->rate;
1346 	if(channels)
1347 		*channels = ao->channels;
1348 	if(encoding)
1349 		*encoding = ao->format;
1350 	if(framesize)
1351 		*framesize = ao->framesize;
1352 	return OUT123_OK;
1353 }
1354 
1355 struct enc_desc
1356 {
1357 	int code; /* MPG123_ENC_SOMETHING */
1358 	const char *longname; /* signed bla bla */
1359 	const char *name; /* sXX, short name */
1360 };
1361 
1362 static const struct enc_desc encdesc[] =
1363 {
1364 	{ MPG123_ENC_SIGNED_16,   "signed 16 bit",   "s16"  }
1365 ,	{ MPG123_ENC_UNSIGNED_16, "unsigned 16 bit", "u16"  }
1366 ,	{ MPG123_ENC_SIGNED_32,   "signed 32 bit",   "s32"  }
1367 ,	{ MPG123_ENC_UNSIGNED_32, "unsigned 32 bit", "u32"  }
1368 ,	{ MPG123_ENC_SIGNED_24,   "signed 24 bit",   "s24"  }
1369 ,	{ MPG123_ENC_UNSIGNED_24, "unsigned 24 bit", "u24"  }
1370 ,	{ MPG123_ENC_FLOAT_32,    "float (32 bit)",  "f32"  }
1371 ,	{ MPG123_ENC_FLOAT_64,    "float (64 bit)",  "f64"  }
1372 ,	{ MPG123_ENC_SIGNED_8,    "signed 8 bit",    "s8"   }
1373 ,	{ MPG123_ENC_UNSIGNED_8,  "unsigned 8 bit",  "u8"   }
1374 ,	{ MPG123_ENC_ULAW_8,      "mu-law (8 bit)",  "ulaw" }
1375 ,	{ MPG123_ENC_ALAW_8,      "a-law (8 bit)",   "alaw" }
1376 };
1377 #define KNOWN_ENCS (sizeof(encdesc)/sizeof(struct enc_desc))
1378 
out123_enc_list(int ** enclist)1379 int attribute_align_arg out123_enc_list(int **enclist)
1380 {
1381 	int i;
1382 	if(!enclist)
1383 		return OUT123_ERR;
1384 	*enclist = malloc(sizeof(int)*KNOWN_ENCS);
1385 	if(!(*enclist))
1386 		return OUT123_ERR;
1387 	for(i=0;i<KNOWN_ENCS;++i)
1388 		(*enclist)[i] = encdesc[i].code;
1389 	return KNOWN_ENCS;
1390 }
1391 
out123_enc_byname(const char * name)1392 int attribute_align_arg out123_enc_byname(const char *name)
1393 {
1394 	int i;
1395 	if(!name)
1396 		return OUT123_ERR;
1397 	for(i=0; i<KNOWN_ENCS; ++i) if(
1398 		!strcasecmp(encdesc[i].name, name)
1399 	||	!strcasecmp(encdesc[i].longname, name)
1400 	)
1401 		return encdesc[i].code;
1402 	return OUT123_ERR;
1403 }
1404 
out123_enc_name(int encoding)1405 const char* attribute_align_arg out123_enc_name(int encoding)
1406 {
1407 	int i;
1408 	for(i=0; i<KNOWN_ENCS; ++i) if(encdesc[i].code == encoding)
1409 		return encdesc[i].name;
1410 	return NULL;
1411 }
1412 
out123_enc_longname(int encoding)1413 const char* attribute_align_arg out123_enc_longname(int encoding)
1414 {
1415 	int i;
1416 	for(i=0; i<KNOWN_ENCS; ++i) if(encdesc[i].code == encoding)
1417 		return encdesc[i].longname;
1418 	return NULL;
1419 }
1420