Recently Written · git

sad

sad (2f30.org simple audio daemon) with a Cygwin/OSS port on branch cygwin

git clone https://github.com/equwal/sad

Log | Files | Refs


output.c (5547 bytes)

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 }