sigap

Very simple audio player and signal based queue manager
git clone git://jacobedwards.org/sigap
Log | Files | Refs | README | LICENSE

ap.c (2415B)


      1 /* Copyright 2021 Jacob R. Edwards
      2  *
      3  * This program is free software: you can redistribute it and/or modify
      4  * it under the terms of the GNU General Public License as published by
      5  * the Free Software Foundation, either version 3 of the License, or
      6  * (at your option) any later version.
      7  *
      8  * This program is distributed in the hope that it will be useful,
      9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11  * GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License
     14  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
     15  */
     16 
     17 #include <errno.h>
     18 #include <limits.h>
     19 #include <poll.h>
     20 #include <string.h>
     21 
     22 #include "ap.h"
     23 
     24 int
     25 sferrno(int error)
     26 {
     27         switch (error) {
     28         case SF_ERR_MALFORMED_FILE:
     29         case SF_ERR_UNRECOGNISED_FORMAT:
     30         case SF_ERR_UNSUPPORTED_ENCODING:
     31                 return EFTYPE;
     32         default:
     33                 return 0;
     34         }
     35 }
     36 
     37 struct ap *
     38 apopen(int fd)
     39 {
     40 	SF_INFO infmt;
     41 	struct ap *ap;
     42 	struct pollfd pfd;
     43 
     44 	if (fd < 0) {
     45 		errno = EBADF;
     46 		return NULL;
     47 	}
     48 
     49 	ap = calloc(1, sizeof(*ap));
     50 	if (ap == NULL)
     51 		return NULL;
     52 
     53 	pfd.fd = fd;
     54 	pfd.events = POLLIN;
     55 	if (poll(&pfd, 1, INFTIM) == -1) {
     56 		free(ap);
     57 		return NULL;
     58 	}
     59 
     60 	ap->in = sf_open_fd(fd, SFM_READ, &infmt, 0);
     61 	if (ap->in == NULL) {
     62 		free(ap);
     63 		errno = sferrno(sf_error(NULL));
     64 		return NULL;
     65 	}
     66 
     67 	ap->fmt.bits = sizeof(sample) * 8;
     68 	ap->fmt.byte_format = AO_FMT_NATIVE;
     69 	ap->fmt.channels = infmt.channels;
     70 	ap->fmt.rate = infmt.samplerate;
     71 
     72 	ap->out = ao_open_live(0, &ap->fmt, NULL);
     73 	if (ap->out == NULL) {
     74 		sf_close(ap->in);
     75 		free(ap);
     76 		return NULL;
     77 	}
     78 
     79 	return ap;
     80 }
     81 
     82 int
     83 apclose(struct ap *ap)
     84 {
     85 	if (ap == NULL)
     86 		return 0;
     87 	return (!!sf_close(ap->in) + !ao_close(ap->out));
     88 }
     89 
     90 ssize_t
     91 applay(struct ap *ap, sample *buf, size_t len)
     92 {
     93 	if (len > SSIZE_MAX) {
     94 		errno = EINVAL;
     95 		return 1;
     96 	}
     97 
     98 	len = sf_read_short(ap->in, buf, len);
     99 	if (len == 0)
    100 		return 0;
    101 	if (len < 0) {
    102 		errno = sferrno(sf_error(ap->in));
    103 		return -1;
    104 	}
    105 
    106 	if (!ao_play(ap->out, (char *)buf, len * sizeof(*buf)))
    107 		return -1;
    108 	return len;
    109 }
    110 
    111 int
    112 ap(int fd)
    113 {
    114 	sample buf[4096];
    115 	ssize_t wrote;
    116 	struct ap *ap;
    117 
    118 	ap = apopen(fd);
    119 	if (ap == NULL)
    120 		return 1;
    121 
    122 	while ((wrote = applay(ap, buf, sizeof(buf) / sizeof(*buf))) > 0)
    123 		;
    124 	return wrote != 0;
    125 }