1 1.27 gson /* $NetBSD: audio.c,v 1.27 2024/02/27 21:05:34 gson Exp $ */ 2 1.2 mrg 3 1.2 mrg /* 4 1.26 mrg * Copyright (c) 1999, 2013, 2015, 2019 Matthew R. Green 5 1.2 mrg * All rights reserved. 6 1.2 mrg * 7 1.2 mrg * Redistribution and use in source and binary forms, with or without 8 1.2 mrg * modification, are permitted provided that the following conditions 9 1.2 mrg * are met: 10 1.2 mrg * 1. Redistributions of source code must retain the above copyright 11 1.2 mrg * notice, this list of conditions and the following disclaimer. 12 1.2 mrg * 2. Redistributions in binary form must reproduce the above copyright 13 1.2 mrg * notice, this list of conditions and the following disclaimer in the 14 1.2 mrg * documentation and/or other materials provided with the distribution. 15 1.2 mrg * 16 1.2 mrg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.2 mrg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.2 mrg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.2 mrg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.2 mrg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 1.2 mrg * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 1.2 mrg * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 1.2 mrg * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 1.2 mrg * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.2 mrg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.2 mrg * SUCH DAMAGE. 27 1.2 mrg */ 28 1.2 mrg 29 1.7 mrg /* 30 1.7 mrg * XXX this is slightly icky in places... 31 1.7 mrg */ 32 1.17 agc #include <sys/cdefs.h> 33 1.17 agc 34 1.17 agc #ifndef lint 35 1.27 gson __RCSID("$NetBSD: audio.c,v 1.27 2024/02/27 21:05:34 gson Exp $"); 36 1.17 agc #endif 37 1.17 agc 38 1.7 mrg 39 1.1 mrg #include <sys/types.h> 40 1.1 mrg #include <sys/audioio.h> 41 1.1 mrg #include <sys/ioctl.h> 42 1.1 mrg #include <sys/time.h> 43 1.22 mrg #include <sys/uio.h> 44 1.1 mrg 45 1.22 mrg #include <unistd.h> 46 1.1 mrg #include <ctype.h> 47 1.1 mrg #include <err.h> 48 1.1 mrg #include <stdio.h> 49 1.1 mrg #include <stdlib.h> 50 1.1 mrg #include <string.h> 51 1.1 mrg 52 1.1 mrg #include "libaudio.h" 53 1.22 mrg #include "auconv.h" 54 1.1 mrg 55 1.14 mrg /* what format am i? */ 56 1.14 mrg 57 1.20 joerg static const struct { 58 1.15 mrg const char *fname; 59 1.14 mrg int fno; 60 1.14 mrg } formats[] = { 61 1.14 mrg { "sunau", AUDIO_FORMAT_SUN }, 62 1.14 mrg { "au", AUDIO_FORMAT_SUN }, 63 1.14 mrg { "sun", AUDIO_FORMAT_SUN }, 64 1.14 mrg { "wav", AUDIO_FORMAT_WAV }, 65 1.14 mrg { "wave", AUDIO_FORMAT_WAV }, 66 1.14 mrg { "riff", AUDIO_FORMAT_WAV }, 67 1.14 mrg { "no", AUDIO_FORMAT_NONE }, 68 1.14 mrg { "none", AUDIO_FORMAT_NONE }, 69 1.14 mrg { NULL, -1 } 70 1.14 mrg }; 71 1.14 mrg 72 1.22 mrg char audio_default_info[8] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' }; 73 1.22 mrg 74 1.14 mrg int 75 1.20 joerg audio_format_from_str(char *str) 76 1.14 mrg { 77 1.14 mrg int i; 78 1.14 mrg 79 1.14 mrg for (i = 0; formats[i].fname; i++) 80 1.14 mrg if (strcasecmp(formats[i].fname, str) == 0) 81 1.14 mrg break; 82 1.14 mrg return (formats[i].fno); 83 1.14 mrg } 84 1.14 mrg 85 1.14 mrg 86 1.14 mrg 87 1.1 mrg /* back and forth between encodings */ 88 1.20 joerg static const struct { 89 1.15 mrg const char *ename; 90 1.1 mrg int eno; 91 1.1 mrg } encs[] = { 92 1.1 mrg { AudioEmulaw, AUDIO_ENCODING_ULAW }, 93 1.1 mrg { "ulaw", AUDIO_ENCODING_ULAW }, 94 1.1 mrg { AudioEalaw, AUDIO_ENCODING_ALAW }, 95 1.1 mrg { AudioEslinear, AUDIO_ENCODING_SLINEAR }, 96 1.1 mrg { "linear", AUDIO_ENCODING_SLINEAR }, 97 1.1 mrg { AudioEulinear, AUDIO_ENCODING_ULINEAR }, 98 1.1 mrg { AudioEadpcm, AUDIO_ENCODING_ADPCM }, 99 1.1 mrg { "ADPCM", AUDIO_ENCODING_ADPCM }, 100 1.1 mrg { AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE }, 101 1.1 mrg { "linear_le", AUDIO_ENCODING_SLINEAR_LE }, 102 1.1 mrg { AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE }, 103 1.1 mrg { AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE }, 104 1.1 mrg { "linear_be", AUDIO_ENCODING_SLINEAR_BE }, 105 1.1 mrg { AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE }, 106 1.1 mrg { AudioEmpeg_l1_stream, AUDIO_ENCODING_MPEG_L1_STREAM }, 107 1.1 mrg { AudioEmpeg_l1_packets,AUDIO_ENCODING_MPEG_L1_PACKETS }, 108 1.1 mrg { AudioEmpeg_l1_system, AUDIO_ENCODING_MPEG_L1_SYSTEM }, 109 1.1 mrg { AudioEmpeg_l2_stream, AUDIO_ENCODING_MPEG_L2_STREAM }, 110 1.1 mrg { AudioEmpeg_l2_packets,AUDIO_ENCODING_MPEG_L2_PACKETS }, 111 1.1 mrg { AudioEmpeg_l2_system, AUDIO_ENCODING_MPEG_L2_SYSTEM }, 112 1.21 jmcneill { AudioEac3, AUDIO_ENCODING_AC3 }, 113 1.26 mrg { "ieee_float32", AUDIO_ENCODING_LIBAUDIO_FLOAT32 }, 114 1.26 mrg { "ieee_float64", AUDIO_ENCODING_LIBAUDIO_FLOAT64 }, 115 1.8 tron { NULL, -1 } 116 1.1 mrg }; 117 1.1 mrg 118 1.1 mrg 119 1.15 mrg const char * 120 1.20 joerg audio_enc_from_val(int val) 121 1.1 mrg { 122 1.1 mrg int i; 123 1.1 mrg 124 1.1 mrg for (i = 0; encs[i].ename; i++) 125 1.1 mrg if (encs[i].eno == val) 126 1.1 mrg break; 127 1.1 mrg return (encs[i].ename); 128 1.1 mrg } 129 1.1 mrg 130 1.1 mrg int 131 1.20 joerg audio_enc_to_val(const char *enc) 132 1.1 mrg { 133 1.1 mrg int i; 134 1.1 mrg 135 1.1 mrg for (i = 0; encs[i].ename; i++) 136 1.1 mrg if (strcmp(encs[i].ename, enc) == 0) 137 1.1 mrg break; 138 1.1 mrg if (encs[i].ename) 139 1.1 mrg return (encs[i].eno); 140 1.1 mrg else 141 1.1 mrg return (AUDIO_ENOENT); 142 1.1 mrg } 143 1.1 mrg 144 1.1 mrg /* 145 1.1 mrg * decode a string into an encoding value. 146 1.1 mrg */ 147 1.1 mrg void 148 1.20 joerg decode_encoding(const char *arg, int *encp) 149 1.1 mrg { 150 1.1 mrg size_t len; 151 1.1 mrg int i; 152 1.1 mrg 153 1.1 mrg len = strlen(arg); 154 1.1 mrg for (i = 0; encs[i].ename; i++) 155 1.1 mrg if (strncmp(encs[i].ename, arg, len) == 0) { 156 1.1 mrg *encp = encs[i].eno; 157 1.1 mrg return; 158 1.1 mrg } 159 1.1 mrg errx(1, "unknown encoding `%s'", arg); 160 1.1 mrg } 161 1.1 mrg 162 1.20 joerg static const char *const audio_errlist[] = { 163 1.9 mrg "error zero", /* nothing? */ 164 1.9 mrg "no audio entry", /* AUDIO_ENOENT */ 165 1.9 mrg "short header", /* AUDIO_ESHORTHDR */ 166 1.9 mrg "unsupported WAV format", /* AUDIO_EWAVUNSUPP */ 167 1.9 mrg "bad (unsupported) WAV PCM format", /* AUDIO_EWAVBADPCM */ 168 1.9 mrg "no WAV audio data", /* AUDIO_EWAVNODATA */ 169 1.14 mrg "internal error", /* AUDIO_EINTERNAL */ 170 1.1 mrg }; 171 1.1 mrg 172 1.1 mrg const char * 173 1.20 joerg audio_errstring(int errval) 174 1.1 mrg { 175 1.1 mrg 176 1.1 mrg errval = -errval; 177 1.1 mrg if (errval < 1 || errval > AUDIO_MAXERRNO) 178 1.1 mrg return "Invalid error"; 179 1.1 mrg return audio_errlist[errval]; 180 1.1 mrg } 181 1.22 mrg 182 1.22 mrg void 183 1.25 mrg write_header(struct track_info *ti) 184 1.22 mrg { 185 1.22 mrg struct iovec iv[3]; 186 1.22 mrg int veclen, left, tlen; 187 1.22 mrg void *hdr; 188 1.22 mrg size_t hdrlen; 189 1.22 mrg 190 1.25 mrg switch (ti->format) { 191 1.22 mrg case AUDIO_FORMAT_DEFAULT: 192 1.22 mrg case AUDIO_FORMAT_SUN: 193 1.25 mrg if (sun_prepare_header(ti, &hdr, &hdrlen, &left) != 0) 194 1.22 mrg return; 195 1.22 mrg break; 196 1.22 mrg case AUDIO_FORMAT_WAV: 197 1.25 mrg if (wav_prepare_header(ti, &hdr, &hdrlen, &left) != 0) 198 1.22 mrg return; 199 1.22 mrg break; 200 1.22 mrg case AUDIO_FORMAT_NONE: 201 1.22 mrg return; 202 1.22 mrg default: 203 1.22 mrg errx(1, "unknown audio format"); 204 1.22 mrg } 205 1.22 mrg 206 1.22 mrg veclen = 0; 207 1.22 mrg tlen = 0; 208 1.27 gson 209 1.22 mrg if (hdrlen != 0) { 210 1.22 mrg iv[veclen].iov_base = hdr; 211 1.22 mrg iv[veclen].iov_len = hdrlen; 212 1.22 mrg tlen += iv[veclen++].iov_len; 213 1.22 mrg } 214 1.25 mrg if (ti->header_info) { 215 1.25 mrg iv[veclen].iov_base = ti->header_info; 216 1.25 mrg iv[veclen].iov_len = (int)strlen(ti->header_info) + 1; 217 1.22 mrg tlen += iv[veclen++].iov_len; 218 1.22 mrg } 219 1.22 mrg if (left) { 220 1.22 mrg iv[veclen].iov_base = audio_default_info; 221 1.22 mrg iv[veclen].iov_len = left; 222 1.22 mrg tlen += iv[veclen++].iov_len; 223 1.22 mrg } 224 1.22 mrg 225 1.22 mrg if (tlen == 0) 226 1.22 mrg return; 227 1.22 mrg 228 1.25 mrg if (writev(ti->outfd, iv, veclen) != tlen) 229 1.22 mrg err(1, "could not write audio header"); 230 1.22 mrg } 231 1.22 mrg 232 1.22 mrg write_conv_func 233 1.25 mrg write_get_conv_func(struct track_info *ti) 234 1.22 mrg { 235 1.22 mrg 236 1.25 mrg switch (ti->format) { 237 1.22 mrg case AUDIO_FORMAT_DEFAULT: 238 1.22 mrg case AUDIO_FORMAT_SUN: 239 1.25 mrg return sun_write_get_conv_func(ti); 240 1.22 mrg case AUDIO_FORMAT_WAV: 241 1.25 mrg return wav_write_get_conv_func(ti); 242 1.22 mrg case AUDIO_FORMAT_NONE: 243 1.22 mrg return NULL; 244 1.22 mrg default: 245 1.22 mrg errx(1, "unknown audio format"); 246 1.22 mrg } 247 1.22 mrg } 248