1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2016 Alex Teaca <iateaca@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 */ 29 30 #include <sys/cdefs.h> 31 #ifndef WITHOUT_CAPSICUM 32 #include <sys/capsicum.h> 33 #include <capsicum_helpers.h> 34 #endif 35 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <fcntl.h> 39 #include <sys/ioctl.h> 40 #include <unistd.h> 41 #include <assert.h> 42 #include <errno.h> 43 #include <err.h> 44 #include <sysexits.h> 45 46 #include "audio.h" 47 #include "pci_hda.h" 48 49 /* 50 * Audio Player internal data structures 51 */ 52 53 struct audio { 54 int fd; 55 uint8_t dir; 56 uint8_t inited; 57 char dev_name[64]; 58 }; 59 60 /* 61 * Audio Player module function definitions 62 */ 63 64 /* 65 * audio_init - initialize an instance of audio player 66 * @dev_name - the backend sound device used to play / capture 67 * @dir - dir = 1 for write mode, dir = 0 for read mode 68 */ 69 struct audio * 70 audio_init(const char *dev_name, uint8_t dir) 71 { 72 struct audio *aud = NULL; 73 #ifndef WITHOUT_CAPSICUM 74 cap_rights_t rights; 75 cap_ioctl_t cmds[] = { 76 SNDCTL_DSP_RESET, SNDCTL_DSP_SETFMT, SNDCTL_DSP_CHANNELS, 77 SNDCTL_DSP_SPEED, 78 #ifdef DEBUG_HDA 79 SNDCTL_DSP_GETOSPACE, SNDCTL_DSP_GETISPACE, 80 #endif 81 }; 82 #endif 83 84 assert(dev_name); 85 86 aud = calloc(1, sizeof(*aud)); 87 if (!aud) 88 return NULL; 89 90 if (strlen(dev_name) < sizeof(aud->dev_name)) 91 memcpy(aud->dev_name, dev_name, strlen(dev_name) + 1); 92 else { 93 DPRINTF("dev_name too big"); 94 free(aud); 95 return NULL; 96 } 97 98 aud->dir = dir; 99 100 aud->fd = open(aud->dev_name, aud->dir ? O_WRONLY : O_RDONLY, 0); 101 if (aud->fd == -1) { 102 DPRINTF("Failed to open dev: %s, errno: %d", 103 aud->dev_name, errno); 104 free(aud); 105 return (NULL); 106 } 107 108 #ifndef WITHOUT_CAPSICUM 109 cap_rights_init(&rights, CAP_IOCTL, CAP_READ, CAP_WRITE); 110 if (caph_rights_limit(aud->fd, &rights) == -1) 111 errx(EX_OSERR, "Unable to apply rights for sandbox"); 112 if (caph_ioctls_limit(aud->fd, cmds, nitems(cmds)) == -1) 113 errx(EX_OSERR, "Unable to limit ioctl rights for sandbox"); 114 #endif 115 116 return aud; 117 } 118 119 /* 120 * audio_set_params - reset the sound device and set the audio params 121 * @aud - the audio player to be configured 122 * @params - the audio parameters to be set 123 */ 124 int 125 audio_set_params(struct audio *aud, struct audio_params *params) 126 { 127 int audio_fd; 128 int format, channels, rate; 129 int err; 130 #if DEBUG_HDA == 1 131 audio_buf_info info; 132 #endif 133 134 assert(aud); 135 assert(params); 136 137 if ((audio_fd = aud->fd) < 0) { 138 DPRINTF("Incorrect audio device descriptor for %s", 139 aud->dev_name); 140 return (-1); 141 } 142 143 /* Reset the device if it was previously opened */ 144 if (aud->inited) { 145 err = ioctl(audio_fd, SNDCTL_DSP_RESET, NULL); 146 if (err == -1) { 147 DPRINTF("Failed to reset fd: %d, errno: %d", 148 aud->fd, errno); 149 return (-1); 150 } 151 } else 152 aud->inited = 1; 153 154 /* Set the Format (Bits per Sample) */ 155 format = params->format; 156 err = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format); 157 if (err == -1) { 158 DPRINTF("Fail to set fmt: 0x%x errno: %d", 159 params->format, errno); 160 return -1; 161 } 162 163 /* The device does not support the requested audio format */ 164 if (format != params->format) { 165 DPRINTF("Mismatch format: 0x%x params->format: 0x%x", 166 format, params->format); 167 return -1; 168 } 169 170 /* Set the Number of Channels */ 171 channels = params->channels; 172 err = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels); 173 if (err == -1) { 174 DPRINTF("Fail to set channels: %d errno: %d", 175 params->channels, errno); 176 return -1; 177 } 178 179 /* The device does not support the requested no. of channels */ 180 if (channels != params->channels) { 181 DPRINTF("Mismatch channels: %d params->channels: %d", 182 channels, params->channels); 183 return -1; 184 } 185 186 /* Set the Sample Rate / Speed */ 187 rate = params->rate; 188 err = ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate); 189 if (err == -1) { 190 DPRINTF("Fail to set speed: %d errno: %d", 191 params->rate, errno); 192 return -1; 193 } 194 195 /* The device does not support the requested rate / speed */ 196 if (rate != params->rate) { 197 DPRINTF("Mismatch rate: %d params->rate: %d", 198 rate, params->rate); 199 return -1; 200 } 201 202 #if DEBUG_HDA == 1 203 err = ioctl(audio_fd, aud->dir ? SNDCTL_DSP_GETOSPACE : 204 SNDCTL_DSP_GETISPACE, &info); 205 if (err == -1) { 206 DPRINTF("Fail to get audio buf info errno: %d", errno); 207 return -1; 208 } 209 DPRINTF("fragstotal: 0x%x fragsize: 0x%x", 210 info.fragstotal, info.fragsize); 211 #endif 212 return 0; 213 } 214 215 /* 216 * audio_playback - plays samples to the sound device using blocking operations 217 * @aud - the audio player used to play the samples 218 * @buf - the buffer containing the samples 219 * @count - the number of bytes in buffer 220 */ 221 int 222 audio_playback(struct audio *aud, const uint8_t *buf, size_t count) 223 { 224 ssize_t len; 225 size_t total; 226 int audio_fd; 227 228 assert(aud); 229 assert(aud->dir); 230 assert(buf); 231 232 audio_fd = aud->fd; 233 assert(audio_fd != -1); 234 235 for (total = 0; total < count; total += len) { 236 len = write(audio_fd, buf + total, count - total); 237 if (len < 0) { 238 DPRINTF("Fail to write to fd: %d, errno: %d", 239 audio_fd, errno); 240 return -1; 241 } 242 } 243 244 return 0; 245 } 246 247 /* 248 * audio_record - records samples from the sound device using 249 * blocking operations. 250 * @aud - the audio player used to capture the samples 251 * @buf - the buffer to receive the samples 252 * @count - the number of bytes to capture in buffer 253 * Returns -1 on error and 0 on success 254 */ 255 int 256 audio_record(struct audio *aud, uint8_t *buf, size_t count) 257 { 258 ssize_t len; 259 size_t total; 260 int audio_fd; 261 262 assert(aud); 263 assert(!aud->dir); 264 assert(buf); 265 266 audio_fd = aud->fd; 267 assert(audio_fd != -1); 268 269 for (total = 0; total < count; total += len) { 270 len = read(audio_fd, buf + total, count - total); 271 if (len < 0) { 272 DPRINTF("Fail to write to fd: %d, errno: %d", 273 audio_fd, errno); 274 return -1; 275 } 276 } 277 278 return 0; 279 } 280