sad

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

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 }