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