]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bhyve/audio.c
sysctl(9): Fix a few mandoc related issues
[FreeBSD/FreeBSD.git] / usr.sbin / bhyve / audio.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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 __FBSDID("$FreeBSD$");
32
33 #ifndef WITHOUT_CAPSICUM
34 #include <sys/capsicum.h>
35 #include <capsicum_helpers.h>
36 #endif
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <fcntl.h>
41 #include <sys/ioctl.h>
42 #include <unistd.h>
43 #include <assert.h>
44 #include <errno.h>
45 #include <err.h>
46 #include <sysexits.h>
47
48 #include "audio.h"
49 #include "pci_hda.h"
50
51 /*
52  * Audio Player internal data structures
53  */
54
55 struct audio {
56         int fd;
57         uint8_t dir;
58         uint8_t inited;
59         char dev_name[64];
60 };
61
62 /*
63  * Audio Player module function definitions
64  */
65
66 /*
67  * audio_init - initialize an instance of audio player
68  * @dev_name - the backend sound device used to play / capture
69  * @dir - dir = 1 for write mode, dir = 0 for read mode
70  */
71 struct audio *
72 audio_init(const char *dev_name, uint8_t dir)
73 {
74         struct audio *aud = NULL;
75 #ifndef WITHOUT_CAPSICUM
76         cap_rights_t rights;
77         cap_ioctl_t cmds[] = {
78             SNDCTL_DSP_RESET, SNDCTL_DSP_SETFMT, SNDCTL_DSP_CHANNELS,
79             SNDCTL_DSP_SPEED,
80 #ifdef DEBUG_HDA
81             SNDCTL_DSP_GETOSPACE, SNDCTL_DSP_GETISPACE,
82 #endif
83         };
84 #endif
85
86         assert(dev_name);
87
88         aud = calloc(1, sizeof(*aud));
89         if (!aud)
90                 return NULL;
91
92         if (strlen(dev_name) < sizeof(aud->dev_name))
93                 memcpy(aud->dev_name, dev_name, strlen(dev_name) + 1);
94         else {
95                 DPRINTF("dev_name too big");
96                 free(aud);
97                 return NULL;
98         }
99
100         aud->dir = dir;
101
102         aud->fd = open(aud->dev_name, aud->dir ? O_WRONLY : O_RDONLY, 0);
103         if (aud->fd == -1) {
104                 DPRINTF("Failed to open dev: %s, errno: %d",
105                     aud->dev_name, errno);
106                 free(aud);
107                 return (NULL);
108         }
109
110 #ifndef WITHOUT_CAPSICUM
111         cap_rights_init(&rights, CAP_IOCTL, CAP_READ, CAP_WRITE);
112         if (caph_rights_limit(aud->fd, &rights) == -1)
113                 errx(EX_OSERR, "Unable to apply rights for sandbox");
114         if (caph_ioctls_limit(aud->fd, cmds, nitems(cmds)) == -1)
115                 errx(EX_OSERR, "Unable to limit ioctl rights for sandbox");
116 #endif
117
118         return aud;
119 }
120
121 /*
122  * audio_set_params - reset the sound device and set the audio params
123  * @aud - the audio player to be configured
124  * @params - the audio parameters to be set
125  */
126 int
127 audio_set_params(struct audio *aud, struct audio_params *params)
128 {
129         int audio_fd;
130         int format, channels, rate;
131         int err;
132 #if DEBUG_HDA == 1
133         audio_buf_info info;
134 #endif
135
136         assert(aud);
137         assert(params);
138
139         if ((audio_fd = aud->fd) < 0) {
140                 DPRINTF("Incorrect audio device descriptor for %s",
141                     aud->dev_name);
142                 return (-1);
143         }
144
145         /* Reset the device if it was previously opened */
146         if (aud->inited) {
147                 err = ioctl(audio_fd, SNDCTL_DSP_RESET, NULL);
148                 if (err == -1) {
149                         DPRINTF("Failed to reset fd: %d, errno: %d",
150                             aud->fd, errno);
151                         return (-1);
152                 }
153         } else
154                 aud->inited = 1;
155
156         /* Set the Format (Bits per Sample) */
157         format = params->format;
158         err = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format);
159         if (err == -1) {
160                 DPRINTF("Fail to set fmt: 0x%x errno: %d",
161                     params->format, errno);
162                 return -1;
163         }
164
165         /* The device does not support the requested audio format */
166         if (format != params->format) {
167                 DPRINTF("Mismatch format: 0x%x params->format: 0x%x",
168                     format, params->format);
169                 return -1;
170         }
171
172         /* Set the Number of Channels */
173         channels = params->channels;
174         err = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels);
175         if (err == -1) {
176                 DPRINTF("Fail to set channels: %d errno: %d",
177                     params->channels, errno);
178                 return -1;
179         }
180
181         /* The device does not support the requested no. of channels */
182         if (channels != params->channels) {
183                 DPRINTF("Mismatch channels: %d params->channels: %d",
184                     channels, params->channels);
185                 return -1;
186         }
187
188         /* Set the Sample Rate / Speed */
189         rate = params->rate;
190         err = ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate);
191         if (err == -1) {
192                 DPRINTF("Fail to set speed: %d errno: %d",
193                     params->rate, errno);
194                 return -1;
195         }
196
197         /* The device does not support the requested rate / speed */
198         if (rate != params->rate) {
199                 DPRINTF("Mismatch rate: %d params->rate: %d",
200                     rate, params->rate);
201                 return -1;
202         }
203
204 #if DEBUG_HDA == 1
205         err = ioctl(audio_fd, aud->dir ? SNDCTL_DSP_GETOSPACE :
206             SNDCTL_DSP_GETISPACE, &info);
207         if (err == -1) {
208                 DPRINTF("Fail to get audio buf info errno: %d", errno);
209                 return -1;
210         }
211         DPRINTF("fragstotal: 0x%x fragsize: 0x%x",
212             info.fragstotal, info.fragsize);
213 #endif
214         return 0;
215 }
216
217 /*
218  * audio_playback - plays samples to the sound device using blocking operations
219  * @aud - the audio player used to play the samples
220  * @buf - the buffer containing the samples
221  * @count - the number of bytes in buffer
222  */
223 int
224 audio_playback(struct audio *aud, const void *buf, size_t count)
225 {
226         int audio_fd = -1;
227         ssize_t len = 0, total = 0;
228
229         assert(aud);
230         assert(aud->dir);
231         assert(buf);
232
233         audio_fd = aud->fd;
234         assert(audio_fd != -1);
235
236         total = 0;
237         while (total < count) {
238                 len = write(audio_fd, buf + total, count - total);
239                 if (len == -1) {
240                         DPRINTF("Fail to write to fd: %d, errno: %d",
241                             audio_fd, errno);
242                         return -1;
243                 }
244
245                 total += len;
246         }
247
248         return 0;
249 }
250
251 /*
252  * audio_record - records samples from the sound device using
253  * blocking operations.
254  * @aud - the audio player used to capture the samples
255  * @buf - the buffer to receive the samples
256  * @count - the number of bytes to capture in buffer
257  * Returns -1 on error and 0 on success
258  */
259 int
260 audio_record(struct audio *aud, void *buf, size_t count)
261 {
262         int audio_fd = -1;
263         ssize_t len = 0, total = 0;
264
265         assert(aud);
266         assert(!aud->dir);
267         assert(buf);
268
269         audio_fd = aud->fd;
270         assert(audio_fd != -1);
271
272         total = 0;
273         while (total < count) {
274                 len = read(audio_fd, buf + total, count - total);
275                 if (len == -1) {
276                         DPRINTF("Fail to write to fd: %d, errno: %d",
277                             audio_fd, errno);
278                         return -1;
279                 }
280
281                 total += len;
282         }
283
284         return 0;
285 }