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 }