Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/bhyve/audio.c
104817 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2016 Alex Teaca <[email protected]>
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
size_t nlen;
84
85
assert(dev_name);
86
87
aud = calloc(1, sizeof(*aud));
88
if (!aud)
89
return NULL;
90
91
nlen = strlen(dev_name);
92
if (nlen < sizeof(aud->dev_name))
93
memcpy(aud->dev_name, dev_name, nlen + 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 uint8_t *buf, size_t count)
225
{
226
ssize_t len;
227
size_t total;
228
int audio_fd;
229
230
assert(aud);
231
assert(aud->dir);
232
assert(buf);
233
234
audio_fd = aud->fd;
235
assert(audio_fd != -1);
236
237
for (total = 0; total < count; total += len) {
238
len = write(audio_fd, buf + total, count - total);
239
if (len < 0) {
240
DPRINTF("Fail to write to fd: %d, errno: %d",
241
audio_fd, errno);
242
return -1;
243
}
244
}
245
246
return 0;
247
}
248
249
/*
250
* audio_record - records samples from the sound device using
251
* blocking operations.
252
* @aud - the audio player used to capture the samples
253
* @buf - the buffer to receive the samples
254
* @count - the number of bytes to capture in buffer
255
* Returns -1 on error and 0 on success
256
*/
257
int
258
audio_record(struct audio *aud, uint8_t *buf, size_t count)
259
{
260
ssize_t len;
261
size_t total;
262
int audio_fd;
263
264
assert(aud);
265
assert(!aud->dir);
266
assert(buf);
267
268
audio_fd = aud->fd;
269
assert(audio_fd != -1);
270
271
for (total = 0; total < count; total += len) {
272
len = read(audio_fd, buf + total, count - total);
273
if (len < 0) {
274
DPRINTF("Fail to write to fd: %d, errno: %d",
275
audio_fd, errno);
276
return -1;
277
}
278
}
279
280
return 0;
281
}
282
283