sad

simple audio daemon
git clone git://git.2f30.org/sad.git
Log | Files | Refs | LICENSE

output.c (5164B)


      1 #include <sys/select.h>
      2 
      3 #include <err.h>
      4 #include <limits.h>
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 #include <string.h>
      8 #include <soxr.h>
      9 
     10 #include "sad.h"
     11 
     12 typedef struct {
     13 	char   *name;
     14 	Format  fmt;
     15 	int     enabled;
     16 	int     active;
     17 	Output *output;
     18 	soxr_t  resampler;
     19 } Outputdesc;
     20 
     21 typedef struct {
     22 	char   *name;
     23 	Format  fmt;
     24 	int     enabled;
     25 	Output *output;
     26 } Outputcfg;
     27 
     28 #include "config.h"
     29 
     30 static Outputdesc outputdescs[LEN(outputcfgs)];
     31 
     32 int
     33 initoutputs(void)
     34 {
     35 	size_t i;
     36 
     37 	for (i = 0; i < LEN(outputcfgs); i++) {
     38 		outputdescs[i].name = outputcfgs[i].name;
     39 		outputdescs[i].fmt = outputcfgs[i].fmt;
     40 		outputdescs[i].enabled = outputcfgs[i].enabled;
     41 		outputdescs[i].output = outputcfgs[i].output;
     42 		outputdescs[i].active = 0;
     43 		outputdescs[i].resampler = NULL;
     44 	}
     45 	return 0;
     46 }
     47 
     48 static int
     49 initresampler(Format *fmt, Outputdesc *desc)
     50 {
     51 	soxr_quality_spec_t quality;
     52 	soxr_io_spec_t      iospec;
     53 
     54 	quality = soxr_quality_spec(RESAMPLEQUALITY, 0);
     55 	iospec = soxr_io_spec(SOXR_INT16_I, SOXR_INT16_I);
     56 
     57 	if (desc->resampler)
     58 		soxr_delete(desc->resampler);
     59 	desc->resampler = soxr_create(fmt->rate, desc->fmt.rate,
     60 	                              desc->fmt.channels,
     61 	                              NULL,
     62 	                              &iospec,
     63 	                              &quality,
     64 	                              NULL);
     65 	if (!desc->resampler) {
     66 		warnx("soxr_create: failed to initialize resampler");
     67 		return -1;
     68 	}
     69 	return 0;
     70 }
     71 
     72 int
     73 initresamplers(Format *fmt)
     74 {
     75 	Outputdesc *desc;
     76 	size_t i;
     77 	int r = 0;
     78 
     79 	for (i = 0; i < LEN(outputdescs); i++) {
     80 		desc = &outputdescs[i];
     81 		if (!desc->enabled)
     82 			continue;
     83 		if (initresampler(fmt, desc) < 0)
     84 			r = -1;
     85 	}
     86 	return r;
     87 }
     88 
     89 static int
     90 openoutput(Outputdesc *desc)
     91 {
     92 	if (desc->active)
     93 		return 0;
     94 
     95 	if (desc->output->open(&desc->fmt) < 0) {
     96 		desc->active = 0;
     97 		return -1;
     98 	}
     99 
    100 	printf("Opened %s output\n", desc->name);
    101 	desc->active = 1;
    102 	return 0;
    103 }
    104 
    105 int
    106 openoutputs(void)
    107 {
    108 	Outputdesc *desc;
    109 	size_t i;
    110 	int r = 0;
    111 
    112 	for (i = 0; i < LEN(outputdescs); i++) {
    113 		desc = &outputdescs[i];
    114 		if (!desc->enabled)
    115 			continue;
    116 		if (openoutput(desc) < 0)
    117 			r = -1;
    118 	}
    119 	return r;
    120 }
    121 
    122 static int
    123 closeoutput(Outputdesc *desc)
    124 {
    125 	if (!desc->active)
    126 		return 0;
    127 
    128 	printf("Closed %s output\n", desc->name);
    129 	desc->active = 0;
    130 	return desc->output->close();
    131 }
    132 
    133 int
    134 closeoutputs(void)
    135 {
    136 	Outputdesc *desc;
    137 	size_t i;
    138 	int r = 0;
    139 
    140 	for (i = 0; i < LEN(outputdescs); i++) {
    141 		desc = &outputdescs[i];
    142 		if (!desc->enabled)
    143 			continue;
    144 		if (closeoutput(desc) < 0)
    145 			r = -1;
    146 	}
    147 	return r;
    148 }
    149 
    150 static int
    151 playoutput(Format *fmt, Outputdesc *desc, void *buf, size_t nbytes)
    152 {
    153 	soxr_error_t e;
    154 	size_t inframes, outframes;
    155 	size_t framesize;
    156 	size_t idone, odone;
    157 	void  *inbuf;
    158 	void  *outbuf;
    159 	float  ratio;
    160 
    161 	if (!desc->active)
    162 		return 0;
    163 
    164 	if (fmt->channels == 1 && desc->fmt.channels == 2) {
    165 		/* perform mono to stereo conversion */
    166 		inbuf = malloc(nbytes * 2);
    167 		if (!inbuf)
    168 			err(1, "malloc");
    169 		s16monotostereo(buf, inbuf, nbytes / 2);
    170 		nbytes *= 2;
    171 	} else if (fmt->channels == 2 && desc->fmt.channels == 1) {
    172 		/* perform stereo to mono conversion */
    173 		inbuf = malloc(nbytes / 2);
    174 		if (!inbuf)
    175 			err(1, "malloc");
    176 		s16stereotomono(buf, inbuf, nbytes / 4);
    177 		nbytes /= 2;
    178 	} else {
    179 		inbuf = malloc(nbytes);
    180 		if (!inbuf)
    181 			err(1, "malloc");
    182 		memcpy(inbuf, buf, nbytes);
    183 	}
    184 
    185 	if (fmt->rate == desc->fmt.rate) {
    186 		if (desc->output->play(inbuf, nbytes) < 0) {
    187 			free(inbuf);
    188 			return -1;
    189 		}
    190 		free(inbuf);
    191 		return 0;
    192 	}
    193 
    194 	/* perform SRC */
    195 	framesize = (desc->fmt.bits + 7) / 8 * desc->fmt.channels;
    196 	inframes = nbytes / framesize;
    197 	ratio = (float)desc->fmt.rate / fmt->rate;
    198 	outframes = inframes * ratio + 1;
    199 	outbuf = malloc(outframes * framesize);
    200 	if (!outbuf)
    201 		err(1, "malloc");
    202 
    203 	e = soxr_process(desc->resampler, inbuf, inframes,
    204 	                 &idone, outbuf, outframes,
    205 	                 &odone);
    206 	if (!e) {
    207 		if (desc->output->play(outbuf, odone * framesize) < 0)
    208 			return -1;
    209 		free(inbuf);
    210 		free(outbuf);
    211 		return 0;
    212 	}
    213 
    214 	warnx("soxr_process: failed");
    215 	free(inbuf);
    216 	free(outbuf);
    217 	return -1;
    218 }
    219 
    220 int
    221 playoutputs(Format *fmt, void *inbuf, size_t nbytes)
    222 {
    223 	Outputdesc *desc;
    224 	size_t i;
    225 	int r = 0;
    226 
    227 	for (i = 0; i < LEN(outputdescs); i++) {
    228 		desc = &outputdescs[i];
    229 		if (!desc->enabled)
    230 			continue;
    231 		if (playoutput(fmt, desc, inbuf, nbytes) < 0)
    232 			r = -1;
    233 	}
    234 	return r;
    235 }
    236 
    237 int
    238 setvol(int vol)
    239 {
    240 	Outputdesc *desc;
    241 	size_t i;
    242 	int r = 0;
    243 
    244 	for (i = 0; i < LEN(outputdescs); i++) {
    245 		desc = &outputdescs[i];
    246 		if (!desc->enabled)
    247 			continue;
    248 		if (desc->output->vol(vol) < 0)
    249 			r = -1;
    250 	}
    251 	return r;
    252 }
    253 
    254 int
    255 enableoutput(const char *name)
    256 {
    257 	Outputdesc *desc;
    258 	size_t i;
    259 
    260 	for (i = 0; i < LEN(outputdescs); i++) {
    261 		desc = &outputdescs[i];
    262 		if (strcmp(desc->name, name))
    263 			continue;
    264 		if (openoutput(desc) < 0) {
    265 			desc->enabled = 0;
    266 			return -1;
    267 		} else {
    268 			desc->enabled = 1;
    269 			return 0;
    270 		}
    271 	}
    272 	return -1;
    273 }
    274 
    275 int
    276 disableoutput(const char *name)
    277 {
    278 	Outputdesc *desc;
    279 	size_t i;
    280 
    281 	for (i = 0; i < LEN(outputdescs); i++) {
    282 		desc = &outputdescs[i];
    283 		if (strcmp(desc->name, name))
    284 			continue;
    285 		desc->enabled = 0;
    286 		return closeoutput(desc);
    287 	}
    288 	return -1;
    289 }