root / oss.c @ 678f2df6
History | View | Annotate | Download (13.4 kB)
1 | 27503323 | bellard | /*
|
---|---|---|---|
2 | 27503323 | bellard | * QEMU OSS Audio output driver
|
3 | 27503323 | bellard | *
|
4 | 27503323 | bellard | * Copyright (c) 2003 Vassili Karpov (malc)
|
5 | 27503323 | bellard | *
|
6 | 27503323 | bellard | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 | 27503323 | bellard | * of this software and associated documentation files (the "Software"), to deal
|
8 | 27503323 | bellard | * in the Software without restriction, including without limitation the rights
|
9 | 27503323 | bellard | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 | 27503323 | bellard | * copies of the Software, and to permit persons to whom the Software is
|
11 | 27503323 | bellard | * furnished to do so, subject to the following conditions:
|
12 | 27503323 | bellard | *
|
13 | 27503323 | bellard | * The above copyright notice and this permission notice shall be included in
|
14 | 27503323 | bellard | * all copies or substantial portions of the Software.
|
15 | 27503323 | bellard | *
|
16 | 27503323 | bellard | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 | 27503323 | bellard | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 | 27503323 | bellard | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 | 27503323 | bellard | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 | 27503323 | bellard | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 | 27503323 | bellard | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 | 27503323 | bellard | * THE SOFTWARE.
|
23 | 27503323 | bellard | */
|
24 | 67b915a5 | bellard | #include "vl.h" |
25 | 67b915a5 | bellard | |
26 | 67b915a5 | bellard | #ifndef _WIN32
|
27 | d329a6fb | bellard | #include <ctype.h> |
28 | 27503323 | bellard | #include <fcntl.h> |
29 | 27503323 | bellard | #include <errno.h> |
30 | 27503323 | bellard | #include <stdio.h> |
31 | 27503323 | bellard | #include <unistd.h> |
32 | 27503323 | bellard | #include <string.h> |
33 | 27503323 | bellard | #include <stdlib.h> |
34 | 27503323 | bellard | #include <limits.h> |
35 | 27503323 | bellard | #include <inttypes.h> |
36 | d329a6fb | bellard | #include <sys/mman.h> |
37 | 27503323 | bellard | #include <sys/types.h> |
38 | 27503323 | bellard | #include <sys/ioctl.h> |
39 | 27503323 | bellard | #include <sys/soundcard.h> |
40 | 27503323 | bellard | |
41 | 27503323 | bellard | |
42 | 27503323 | bellard | /* http://www.df.lth.se/~john_e/gems/gem002d.html */
|
43 | 27503323 | bellard | /* http://www.multi-platforms.com/Tips/PopCount.htm */
|
44 | 27503323 | bellard | static inline uint32_t popcount (uint32_t u) |
45 | 27503323 | bellard | { |
46 | 27503323 | bellard | u = ((u&0x55555555) + ((u>>1)&0x55555555)); |
47 | 27503323 | bellard | u = ((u&0x33333333) + ((u>>2)&0x33333333)); |
48 | 27503323 | bellard | u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f)); |
49 | 27503323 | bellard | u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff)); |
50 | 27503323 | bellard | u = ( u&0x0000ffff) + (u>>16); |
51 | 27503323 | bellard | return u;
|
52 | 27503323 | bellard | } |
53 | 27503323 | bellard | |
54 | 27503323 | bellard | static inline uint32_t lsbindex (uint32_t u) |
55 | 27503323 | bellard | { |
56 | 27503323 | bellard | return popcount ((u&-u)-1); |
57 | 27503323 | bellard | } |
58 | 27503323 | bellard | |
59 | 27503323 | bellard | #define MIN(a, b) ((a)>(b)?(b):(a))
|
60 | 27503323 | bellard | #define MAX(a, b) ((a)<(b)?(b):(a))
|
61 | 27503323 | bellard | |
62 | 27503323 | bellard | #define DEREF(x) (void)x |
63 | 27503323 | bellard | #define log(...) fprintf (stderr, "oss: " __VA_ARGS__) |
64 | 27503323 | bellard | #define ERRFail(...) do { \ |
65 | 27503323 | bellard | int _errno = errno; \
|
66 | 27503323 | bellard | fprintf (stderr, "oss: " __VA_ARGS__); \
|
67 | 27503323 | bellard | fprintf (stderr, "system error: %s\n", strerror (_errno)); \
|
68 | 27503323 | bellard | abort (); \ |
69 | 27503323 | bellard | } while (0) |
70 | 27503323 | bellard | #define Fail(...) do { \ |
71 | 27503323 | bellard | fprintf (stderr, "oss: " __VA_ARGS__); \
|
72 | 27503323 | bellard | fprintf (stderr, "\n"); \
|
73 | 27503323 | bellard | abort (); \ |
74 | 27503323 | bellard | } while (0) |
75 | 27503323 | bellard | |
76 | 27503323 | bellard | #ifdef DEBUG_OSS
|
77 | 27503323 | bellard | #define lwarn(...) fprintf (stderr, "oss: " __VA_ARGS__) |
78 | 27503323 | bellard | #define linfo(...) fprintf (stderr, "oss: " __VA_ARGS__) |
79 | 27503323 | bellard | #define ldebug(...) fprintf (stderr, "oss: " __VA_ARGS__) |
80 | 27503323 | bellard | #else
|
81 | 27503323 | bellard | #define lwarn(...)
|
82 | 27503323 | bellard | #define linfo(...)
|
83 | 27503323 | bellard | #define ldebug(...)
|
84 | 27503323 | bellard | #endif
|
85 | 27503323 | bellard | |
86 | 27503323 | bellard | |
87 | 27503323 | bellard | #define IOCTL(args) do { \ |
88 | 27503323 | bellard | int ret = ioctl args; \
|
89 | 27503323 | bellard | if (-1 == ret) { \ |
90 | 27503323 | bellard | ERRFail (#args); \
|
91 | 27503323 | bellard | } \ |
92 | 27503323 | bellard | ldebug ("ioctl " #args " = %d\n", ret); \ |
93 | 27503323 | bellard | } while (0) |
94 | 27503323 | bellard | |
95 | d329a6fb | bellard | static struct { |
96 | d329a6fb | bellard | int fd;
|
97 | d329a6fb | bellard | int freq;
|
98 | d329a6fb | bellard | int bits16;
|
99 | d329a6fb | bellard | int nchannels;
|
100 | d329a6fb | bellard | int rpos;
|
101 | d329a6fb | bellard | int wpos;
|
102 | d329a6fb | bellard | int live;
|
103 | d329a6fb | bellard | int oss_fmt;
|
104 | d329a6fb | bellard | int bytes_per_second;
|
105 | d329a6fb | bellard | int is_mapped;
|
106 | d329a6fb | bellard | void *buf;
|
107 | d329a6fb | bellard | int bufsize;
|
108 | d329a6fb | bellard | int nfrags;
|
109 | d329a6fb | bellard | int fragsize;
|
110 | d329a6fb | bellard | int old_optr;
|
111 | d329a6fb | bellard | int leftover;
|
112 | d329a6fb | bellard | uint64_t old_ticks; |
113 | d329a6fb | bellard | void (*copy_fn)(void *, void *, int); |
114 | d329a6fb | bellard | } oss = { .fd = -1 };
|
115 | d329a6fb | bellard | |
116 | d329a6fb | bellard | static struct { |
117 | d329a6fb | bellard | int try_mmap;
|
118 | d329a6fb | bellard | int nfrags;
|
119 | d329a6fb | bellard | int fragsize;
|
120 | d329a6fb | bellard | } conf = { |
121 | d329a6fb | bellard | .try_mmap = 0,
|
122 | d329a6fb | bellard | .nfrags = 4,
|
123 | d329a6fb | bellard | .fragsize = 4096
|
124 | d329a6fb | bellard | }; |
125 | d329a6fb | bellard | |
126 | d329a6fb | bellard | static enum {DONT, DSP, TID} est = DONT; |
127 | 27503323 | bellard | |
128 | 27503323 | bellard | static void copy_no_conversion (void *dst, void *src, int size) |
129 | 27503323 | bellard | { |
130 | 27503323 | bellard | memcpy (dst, src, size); |
131 | 27503323 | bellard | } |
132 | 27503323 | bellard | |
133 | 27503323 | bellard | static void copy_u16_to_s16 (void *dst, void *src, int size) |
134 | 27503323 | bellard | { |
135 | 27503323 | bellard | int i;
|
136 | 27503323 | bellard | uint16_t *out, *in; |
137 | 27503323 | bellard | |
138 | 27503323 | bellard | out = dst; |
139 | 27503323 | bellard | in = src; |
140 | 27503323 | bellard | |
141 | 27503323 | bellard | for (i = 0; i < size / 2; i++) { |
142 | 27503323 | bellard | out[i] = in[i] + 0x8000;
|
143 | 27503323 | bellard | } |
144 | 27503323 | bellard | } |
145 | 27503323 | bellard | |
146 | 27503323 | bellard | static void pab (struct audio_buf_info *abinfo) |
147 | 27503323 | bellard | { |
148 | 27503323 | bellard | DEREF (abinfo); |
149 | 27503323 | bellard | |
150 | 27503323 | bellard | ldebug ("fragments %d, fragstotal %d, fragsize %d, bytes %d\n"
|
151 | 27503323 | bellard | "rpos %d, wpos %d, live %d\n",
|
152 | 27503323 | bellard | abinfo->fragments, |
153 | 27503323 | bellard | abinfo->fragstotal, |
154 | 27503323 | bellard | abinfo->fragsize, |
155 | 27503323 | bellard | abinfo->bytes, |
156 | 27503323 | bellard | rpos, wpos, live); |
157 | 27503323 | bellard | } |
158 | 27503323 | bellard | |
159 | d329a6fb | bellard | static void do_open () |
160 | 27503323 | bellard | { |
161 | d329a6fb | bellard | int mmmmssss;
|
162 | d329a6fb | bellard | audio_buf_info abinfo; |
163 | d329a6fb | bellard | int fmt, freq, nchannels;
|
164 | 27503323 | bellard | |
165 | d329a6fb | bellard | if (oss.buf) {
|
166 | d329a6fb | bellard | if (-1 == munmap (oss.buf, oss.bufsize)) { |
167 | d329a6fb | bellard | ERRFail ("failed to unmap audio buffer %p %d",
|
168 | d329a6fb | bellard | oss.buf, oss.bufsize); |
169 | d329a6fb | bellard | } |
170 | d329a6fb | bellard | oss.buf = NULL;
|
171 | 27503323 | bellard | } |
172 | 27503323 | bellard | |
173 | d329a6fb | bellard | if (-1 != oss.fd) |
174 | d329a6fb | bellard | close (oss.fd); |
175 | 27503323 | bellard | |
176 | d329a6fb | bellard | oss.fd = open ("/dev/dsp", O_RDWR | O_NONBLOCK);
|
177 | d329a6fb | bellard | if (-1 == oss.fd) { |
178 | d329a6fb | bellard | ERRFail ("can not open /dev/dsp");
|
179 | d329a6fb | bellard | } |
180 | 27503323 | bellard | |
181 | d329a6fb | bellard | fmt = oss.oss_fmt; |
182 | d329a6fb | bellard | freq = oss.freq; |
183 | d329a6fb | bellard | nchannels = oss.nchannels; |
184 | d329a6fb | bellard | |
185 | d329a6fb | bellard | IOCTL ((oss.fd, SNDCTL_DSP_RESET, 1));
|
186 | d329a6fb | bellard | IOCTL ((oss.fd, SNDCTL_DSP_SAMPLESIZE, &fmt)); |
187 | d329a6fb | bellard | IOCTL ((oss.fd, SNDCTL_DSP_CHANNELS, &nchannels)); |
188 | d329a6fb | bellard | IOCTL ((oss.fd, SNDCTL_DSP_SPEED, &freq)); |
189 | d329a6fb | bellard | IOCTL ((oss.fd, SNDCTL_DSP_NONBLOCK)); |
190 | d329a6fb | bellard | |
191 | d329a6fb | bellard | mmmmssss = (conf.nfrags << 16) | conf.fragsize;
|
192 | d329a6fb | bellard | IOCTL ((oss.fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)); |
193 | d329a6fb | bellard | |
194 | d329a6fb | bellard | if ((oss.oss_fmt != fmt)
|
195 | d329a6fb | bellard | || (oss.nchannels != nchannels) |
196 | d329a6fb | bellard | || (oss.freq != freq)) { |
197 | d329a6fb | bellard | Fail ("failed to set audio parameters\n"
|
198 | d329a6fb | bellard | "parameter | requested value | obtained value\n"
|
199 | d329a6fb | bellard | "format | %10d | %10d\n"
|
200 | d329a6fb | bellard | "channels | %10d | %10d\n"
|
201 | d329a6fb | bellard | "frequency | %10d | %10d\n",
|
202 | d329a6fb | bellard | oss.oss_fmt, fmt, |
203 | d329a6fb | bellard | oss.nchannels, nchannels, |
204 | d329a6fb | bellard | oss.freq, freq); |
205 | d329a6fb | bellard | } |
206 | 27503323 | bellard | |
207 | d329a6fb | bellard | IOCTL ((oss.fd, SNDCTL_DSP_GETOSPACE, &abinfo)); |
208 | 27503323 | bellard | |
209 | d329a6fb | bellard | oss.nfrags = abinfo.fragstotal; |
210 | d329a6fb | bellard | oss.fragsize = abinfo.fragsize; |
211 | d329a6fb | bellard | oss.bufsize = oss.nfrags * oss.fragsize; |
212 | d329a6fb | bellard | oss.old_optr = 0;
|
213 | 27503323 | bellard | |
214 | d329a6fb | bellard | oss.bytes_per_second = (freq << (nchannels >> 1)) << oss.bits16;
|
215 | d329a6fb | bellard | |
216 | d329a6fb | bellard | linfo ("bytes per second %d\n", oss.bytes_per_second);
|
217 | d329a6fb | bellard | |
218 | d329a6fb | bellard | linfo ("fragments %d, fragstotal %d, fragsize %d, bytes %d, bufsize %d\n",
|
219 | d329a6fb | bellard | abinfo.fragments, |
220 | d329a6fb | bellard | abinfo.fragstotal, |
221 | d329a6fb | bellard | abinfo.fragsize, |
222 | d329a6fb | bellard | abinfo.bytes, |
223 | d329a6fb | bellard | oss.bufsize); |
224 | d329a6fb | bellard | |
225 | d329a6fb | bellard | oss.buf = MAP_FAILED; |
226 | d329a6fb | bellard | oss.is_mapped = 0;
|
227 | d329a6fb | bellard | |
228 | d329a6fb | bellard | if (conf.try_mmap) {
|
229 | d329a6fb | bellard | oss.buf = mmap (NULL, oss.bufsize, PROT_WRITE, MAP_SHARED, oss.fd, 0); |
230 | d329a6fb | bellard | if (MAP_FAILED == oss.buf) {
|
231 | d329a6fb | bellard | int err;
|
232 | d329a6fb | bellard | |
233 | d329a6fb | bellard | err = errno; |
234 | d329a6fb | bellard | log ("failed to mmap audio, size %d, fd %d\n"
|
235 | d329a6fb | bellard | "syserr: %s\n",
|
236 | d329a6fb | bellard | oss.bufsize, oss.fd, strerror (err)); |
237 | d329a6fb | bellard | } |
238 | 27503323 | bellard | else {
|
239 | d329a6fb | bellard | est = TID; |
240 | d329a6fb | bellard | oss.is_mapped = 1;
|
241 | d329a6fb | bellard | } |
242 | d329a6fb | bellard | } |
243 | d329a6fb | bellard | |
244 | d329a6fb | bellard | if (MAP_FAILED == oss.buf) {
|
245 | d329a6fb | bellard | est = TID; |
246 | d329a6fb | bellard | oss.buf = mmap (NULL, oss.bufsize, PROT_READ | PROT_WRITE,
|
247 | d329a6fb | bellard | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); |
248 | d329a6fb | bellard | if (MAP_FAILED == oss.buf) {
|
249 | d329a6fb | bellard | ERRFail ("mmap audio buf, size %d", oss.bufsize);
|
250 | d329a6fb | bellard | } |
251 | d329a6fb | bellard | } |
252 | d329a6fb | bellard | |
253 | d329a6fb | bellard | oss.rpos = 0;
|
254 | d329a6fb | bellard | oss.wpos = 0;
|
255 | d329a6fb | bellard | oss.live = 0;
|
256 | d329a6fb | bellard | |
257 | d329a6fb | bellard | if (oss.is_mapped) {
|
258 | d329a6fb | bellard | int trig;
|
259 | d329a6fb | bellard | |
260 | d329a6fb | bellard | trig = 0;
|
261 | d329a6fb | bellard | IOCTL ((oss.fd, SNDCTL_DSP_SETTRIGGER, &trig)); |
262 | d329a6fb | bellard | trig = PCM_ENABLE_OUTPUT; |
263 | d329a6fb | bellard | IOCTL ((oss.fd, SNDCTL_DSP_SETTRIGGER, &trig)); |
264 | 27503323 | bellard | } |
265 | 27503323 | bellard | } |
266 | 27503323 | bellard | |
267 | d329a6fb | bellard | static void maybe_open (int req_freq, int req_nchannels, |
268 | d329a6fb | bellard | audfmt_e req_fmt, int force_open)
|
269 | 27503323 | bellard | { |
270 | d329a6fb | bellard | int oss_fmt, bits16;
|
271 | 27503323 | bellard | |
272 | d329a6fb | bellard | switch (req_fmt) {
|
273 | 27503323 | bellard | case AUD_FMT_U8:
|
274 | 27503323 | bellard | bits16 = 0;
|
275 | d329a6fb | bellard | oss_fmt = AFMT_U8; |
276 | d329a6fb | bellard | oss.copy_fn = copy_no_conversion; |
277 | 27503323 | bellard | break;
|
278 | 27503323 | bellard | |
279 | 27503323 | bellard | case AUD_FMT_S8:
|
280 | 27503323 | bellard | Fail ("can not play 8bit signed");
|
281 | 27503323 | bellard | |
282 | 27503323 | bellard | case AUD_FMT_S16:
|
283 | 27503323 | bellard | bits16 = 1;
|
284 | d329a6fb | bellard | oss_fmt = AFMT_S16_LE; |
285 | d329a6fb | bellard | oss.copy_fn = copy_no_conversion; |
286 | 27503323 | bellard | break;
|
287 | 27503323 | bellard | |
288 | 27503323 | bellard | case AUD_FMT_U16:
|
289 | 27503323 | bellard | bits16 = 1;
|
290 | d329a6fb | bellard | oss_fmt = AFMT_S16_LE; |
291 | d329a6fb | bellard | oss.copy_fn = copy_u16_to_s16; |
292 | 27503323 | bellard | break;
|
293 | 27503323 | bellard | |
294 | 27503323 | bellard | default:
|
295 | 27503323 | bellard | abort (); |
296 | 27503323 | bellard | } |
297 | 27503323 | bellard | |
298 | d329a6fb | bellard | if (force_open
|
299 | d329a6fb | bellard | || (-1 == oss.fd)
|
300 | d329a6fb | bellard | || (oss_fmt != oss.oss_fmt) |
301 | d329a6fb | bellard | || (req_nchannels != oss.nchannels) |
302 | d329a6fb | bellard | || (req_freq != oss.freq) |
303 | d329a6fb | bellard | || (bits16 != oss.bits16)) { |
304 | d329a6fb | bellard | oss.oss_fmt = oss_fmt; |
305 | d329a6fb | bellard | oss.nchannels = req_nchannels; |
306 | d329a6fb | bellard | oss.freq = req_freq; |
307 | d329a6fb | bellard | oss.bits16 = bits16; |
308 | d329a6fb | bellard | do_open (); |
309 | 27503323 | bellard | } |
310 | d329a6fb | bellard | } |
311 | 27503323 | bellard | |
312 | d329a6fb | bellard | void AUD_reset (int req_freq, int req_nchannels, audfmt_e req_fmt) |
313 | d329a6fb | bellard | { |
314 | d329a6fb | bellard | maybe_open (req_freq, req_nchannels, req_fmt, 0);
|
315 | d329a6fb | bellard | } |
316 | 27503323 | bellard | |
317 | d329a6fb | bellard | void AUD_open (int req_freq, int req_nchannels, audfmt_e req_fmt) |
318 | d329a6fb | bellard | { |
319 | d329a6fb | bellard | maybe_open (req_freq, req_nchannels, req_fmt, 1);
|
320 | 27503323 | bellard | } |
321 | 27503323 | bellard | |
322 | 27503323 | bellard | int AUD_write (void *in_buf, int size) |
323 | 27503323 | bellard | { |
324 | 27503323 | bellard | int to_copy, temp;
|
325 | 27503323 | bellard | uint8_t *in, *out; |
326 | 27503323 | bellard | |
327 | d329a6fb | bellard | to_copy = MIN (oss.bufsize - oss.live, size); |
328 | 27503323 | bellard | |
329 | 27503323 | bellard | temp = to_copy; |
330 | 27503323 | bellard | |
331 | 27503323 | bellard | in = in_buf; |
332 | d329a6fb | bellard | out = oss.buf; |
333 | 27503323 | bellard | |
334 | 27503323 | bellard | while (temp) {
|
335 | 27503323 | bellard | int copy;
|
336 | 27503323 | bellard | |
337 | d329a6fb | bellard | copy = MIN (temp, oss.bufsize - oss.wpos); |
338 | d329a6fb | bellard | oss.copy_fn (out + oss.wpos, in, copy); |
339 | 27503323 | bellard | |
340 | d329a6fb | bellard | oss.wpos += copy; |
341 | d329a6fb | bellard | if (oss.wpos == oss.bufsize) {
|
342 | d329a6fb | bellard | oss.wpos = 0;
|
343 | 27503323 | bellard | } |
344 | 27503323 | bellard | |
345 | 27503323 | bellard | temp -= copy; |
346 | 27503323 | bellard | in += copy; |
347 | d329a6fb | bellard | oss.live += copy; |
348 | 27503323 | bellard | } |
349 | 27503323 | bellard | |
350 | 27503323 | bellard | return to_copy;
|
351 | 27503323 | bellard | } |
352 | 27503323 | bellard | |
353 | 27503323 | bellard | void AUD_run (void) |
354 | 27503323 | bellard | { |
355 | 27503323 | bellard | int res;
|
356 | 27503323 | bellard | int bytes;
|
357 | 27503323 | bellard | struct audio_buf_info abinfo;
|
358 | 27503323 | bellard | |
359 | d329a6fb | bellard | if (0 == oss.live) |
360 | 27503323 | bellard | return;
|
361 | 27503323 | bellard | |
362 | d329a6fb | bellard | if (oss.is_mapped) {
|
363 | d329a6fb | bellard | count_info info; |
364 | d329a6fb | bellard | |
365 | d329a6fb | bellard | res = ioctl (oss.fd, SNDCTL_DSP_GETOPTR, &info); |
366 | d329a6fb | bellard | if (-1 == res) { |
367 | d329a6fb | bellard | int err;
|
368 | d329a6fb | bellard | |
369 | d329a6fb | bellard | err = errno; |
370 | d329a6fb | bellard | lwarn ("SNDCTL_DSP_GETOPTR failed with %s\n", strerror (err));
|
371 | d329a6fb | bellard | return;
|
372 | d329a6fb | bellard | } |
373 | d329a6fb | bellard | |
374 | d329a6fb | bellard | if (info.ptr > oss.old_optr) {
|
375 | d329a6fb | bellard | bytes = info.ptr - oss.old_optr; |
376 | d329a6fb | bellard | } |
377 | d329a6fb | bellard | else {
|
378 | d329a6fb | bellard | bytes = oss.bufsize + info.ptr - oss.old_optr; |
379 | d329a6fb | bellard | } |
380 | d329a6fb | bellard | |
381 | d329a6fb | bellard | oss.old_optr = info.ptr; |
382 | d329a6fb | bellard | oss.live -= bytes; |
383 | d329a6fb | bellard | return;
|
384 | d329a6fb | bellard | } |
385 | d329a6fb | bellard | |
386 | d329a6fb | bellard | res = ioctl (oss.fd, SNDCTL_DSP_GETOSPACE, &abinfo); |
387 | 27503323 | bellard | |
388 | 27503323 | bellard | if (-1 == res) { |
389 | 27503323 | bellard | int err;
|
390 | 27503323 | bellard | |
391 | 27503323 | bellard | err = errno; |
392 | 27503323 | bellard | lwarn ("SNDCTL_DSP_GETOSPACE failed with %s\n", strerror (err));
|
393 | 27503323 | bellard | } |
394 | 27503323 | bellard | |
395 | 27503323 | bellard | bytes = abinfo.bytes; |
396 | d329a6fb | bellard | bytes = MIN (oss.live, bytes); |
397 | 27503323 | bellard | #if 0
|
398 | 27503323 | bellard | bytes = (bytes / fragsize) * fragsize;
|
399 | 27503323 | bellard | #endif
|
400 | 27503323 | bellard | |
401 | 27503323 | bellard | while (bytes) {
|
402 | 27503323 | bellard | int left, play, written;
|
403 | 27503323 | bellard | |
404 | d329a6fb | bellard | left = oss.bufsize - oss.rpos; |
405 | 27503323 | bellard | play = MIN (left, bytes); |
406 | d329a6fb | bellard | written = write (oss.fd, (void *) ((uint32_t) oss.buf + oss.rpos), play);
|
407 | 27503323 | bellard | |
408 | 27503323 | bellard | if (-1 == written) { |
409 | 27503323 | bellard | if (EAGAIN == errno || EINTR == errno) {
|
410 | 27503323 | bellard | return;
|
411 | 27503323 | bellard | } |
412 | 27503323 | bellard | else {
|
413 | 27503323 | bellard | ERRFail ("write audio");
|
414 | 27503323 | bellard | } |
415 | 27503323 | bellard | } |
416 | 27503323 | bellard | |
417 | 27503323 | bellard | play = written; |
418 | d329a6fb | bellard | oss.live -= play; |
419 | d329a6fb | bellard | oss.rpos += play; |
420 | 27503323 | bellard | bytes -= play; |
421 | 27503323 | bellard | |
422 | d329a6fb | bellard | if (oss.rpos == oss.bufsize) {
|
423 | d329a6fb | bellard | oss.rpos = 0;
|
424 | 27503323 | bellard | } |
425 | 27503323 | bellard | } |
426 | 27503323 | bellard | } |
427 | 27503323 | bellard | |
428 | 27503323 | bellard | static int get_dsp_bytes (void) |
429 | 27503323 | bellard | { |
430 | 27503323 | bellard | int res;
|
431 | 27503323 | bellard | struct count_info info;
|
432 | 27503323 | bellard | |
433 | d329a6fb | bellard | res = ioctl (oss.fd, SNDCTL_DSP_GETOPTR, &info); |
434 | 27503323 | bellard | if (-1 == res) { |
435 | 27503323 | bellard | int err;
|
436 | 27503323 | bellard | |
437 | 27503323 | bellard | err = errno; |
438 | 27503323 | bellard | lwarn ("SNDCTL_DSP_GETOPTR failed with %s\n", strerror (err));
|
439 | 27503323 | bellard | return -1; |
440 | 27503323 | bellard | } |
441 | 27503323 | bellard | else {
|
442 | 27503323 | bellard | ldebug ("bytes %d\n", info.bytes);
|
443 | 27503323 | bellard | return info.bytes;
|
444 | 27503323 | bellard | } |
445 | 27503323 | bellard | } |
446 | 27503323 | bellard | |
447 | d329a6fb | bellard | void AUD_adjust_estimate (int leftover) |
448 | 27503323 | bellard | { |
449 | d329a6fb | bellard | oss.leftover = leftover; |
450 | 27503323 | bellard | } |
451 | 27503323 | bellard | |
452 | 27503323 | bellard | int AUD_get_free (void) |
453 | 27503323 | bellard | { |
454 | 27503323 | bellard | int free, elapsed;
|
455 | 27503323 | bellard | |
456 | d329a6fb | bellard | free = oss.bufsize - oss.live; |
457 | 27503323 | bellard | |
458 | 27503323 | bellard | if (0 == free) |
459 | 27503323 | bellard | return 0; |
460 | 27503323 | bellard | |
461 | 27503323 | bellard | elapsed = free; |
462 | d329a6fb | bellard | switch (est) {
|
463 | 27503323 | bellard | case DONT:
|
464 | 27503323 | bellard | break;
|
465 | 27503323 | bellard | |
466 | 27503323 | bellard | case DSP:
|
467 | 27503323 | bellard | { |
468 | 27503323 | bellard | static int old_bytes; |
469 | 27503323 | bellard | int bytes;
|
470 | 27503323 | bellard | |
471 | 27503323 | bellard | bytes = get_dsp_bytes (); |
472 | 27503323 | bellard | if (bytes <= 0) |
473 | 27503323 | bellard | return free;
|
474 | 27503323 | bellard | |
475 | 27503323 | bellard | elapsed = bytes - old_bytes; |
476 | 27503323 | bellard | old_bytes = bytes; |
477 | 27503323 | bellard | ldebug ("dsp elapsed %d bytes\n", elapsed);
|
478 | 27503323 | bellard | break;
|
479 | 27503323 | bellard | } |
480 | 27503323 | bellard | |
481 | 27503323 | bellard | case TID:
|
482 | 27503323 | bellard | { |
483 | 27503323 | bellard | uint64_t ticks, delta; |
484 | 27503323 | bellard | uint64_t ua_elapsed; |
485 | 27503323 | bellard | uint64_t al_elapsed; |
486 | 27503323 | bellard | |
487 | 8a7ddc38 | bellard | ticks = qemu_get_clock(rt_clock); |
488 | d329a6fb | bellard | delta = ticks - oss.old_ticks; |
489 | d329a6fb | bellard | oss.old_ticks = ticks; |
490 | 27503323 | bellard | |
491 | d329a6fb | bellard | ua_elapsed = (delta * oss.bytes_per_second) / 1000;
|
492 | 27503323 | bellard | al_elapsed = ua_elapsed & ~3ULL;
|
493 | 27503323 | bellard | |
494 | 27503323 | bellard | ldebug ("tid elapsed %llu bytes\n", ua_elapsed);
|
495 | 27503323 | bellard | |
496 | 27503323 | bellard | if (al_elapsed > (uint64_t) INT_MAX)
|
497 | 27503323 | bellard | elapsed = INT_MAX; |
498 | 27503323 | bellard | else
|
499 | 27503323 | bellard | elapsed = al_elapsed; |
500 | 27503323 | bellard | |
501 | d329a6fb | bellard | elapsed += oss.leftover; |
502 | 27503323 | bellard | } |
503 | 27503323 | bellard | } |
504 | 27503323 | bellard | |
505 | 27503323 | bellard | if (elapsed > free) {
|
506 | 27503323 | bellard | lwarn ("audio can not keep up elapsed %d free %d\n", elapsed, free);
|
507 | 27503323 | bellard | return free;
|
508 | 27503323 | bellard | } |
509 | 27503323 | bellard | else {
|
510 | 27503323 | bellard | return elapsed;
|
511 | 27503323 | bellard | } |
512 | 27503323 | bellard | } |
513 | 27503323 | bellard | |
514 | 27503323 | bellard | int AUD_get_live (void) |
515 | 27503323 | bellard | { |
516 | d329a6fb | bellard | return oss.live;
|
517 | 27503323 | bellard | } |
518 | 27503323 | bellard | |
519 | 27503323 | bellard | int AUD_get_buffer_size (void) |
520 | 27503323 | bellard | { |
521 | d329a6fb | bellard | return oss.bufsize;
|
522 | d329a6fb | bellard | } |
523 | d329a6fb | bellard | |
524 | d329a6fb | bellard | #define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE" |
525 | d329a6fb | bellard | #define QC_OSS_NFRAGS "QEMU_OSS_NFRAGS" |
526 | d329a6fb | bellard | #define QC_OSS_MMAP "QEMU_OSS_MMAP" |
527 | d329a6fb | bellard | |
528 | d329a6fb | bellard | static int get_conf_val (const char *key, int defval) |
529 | d329a6fb | bellard | { |
530 | d329a6fb | bellard | int val = defval;
|
531 | d329a6fb | bellard | char *strval;
|
532 | d329a6fb | bellard | |
533 | d329a6fb | bellard | strval = getenv (key); |
534 | d329a6fb | bellard | if (strval) {
|
535 | d329a6fb | bellard | val = atoi (strval); |
536 | d329a6fb | bellard | } |
537 | d329a6fb | bellard | |
538 | d329a6fb | bellard | return val;
|
539 | 27503323 | bellard | } |
540 | 27503323 | bellard | |
541 | 27503323 | bellard | void AUD_init (void) |
542 | 27503323 | bellard | { |
543 | 27503323 | bellard | int fsp;
|
544 | 27503323 | bellard | |
545 | 27503323 | bellard | DEREF (pab); |
546 | 27503323 | bellard | |
547 | d329a6fb | bellard | conf.fragsize = get_conf_val (QC_OSS_FRAGSIZE, conf.fragsize); |
548 | d329a6fb | bellard | conf.nfrags = get_conf_val (QC_OSS_NFRAGS, conf.nfrags); |
549 | d329a6fb | bellard | conf.try_mmap = get_conf_val (QC_OSS_MMAP, conf.try_mmap); |
550 | d329a6fb | bellard | |
551 | d329a6fb | bellard | fsp = conf.fragsize; |
552 | 27503323 | bellard | if (0 != (fsp & (fsp - 1))) { |
553 | 27503323 | bellard | Fail ("fragment size %d is not power of 2", fsp);
|
554 | 27503323 | bellard | } |
555 | 27503323 | bellard | |
556 | d329a6fb | bellard | conf.fragsize = lsbindex (fsp); |
557 | 27503323 | bellard | } |
558 | 67b915a5 | bellard | |
559 | 67b915a5 | bellard | #else
|
560 | 67b915a5 | bellard | |
561 | 67b915a5 | bellard | void AUD_run (void) |
562 | 67b915a5 | bellard | { |
563 | 67b915a5 | bellard | } |
564 | 67b915a5 | bellard | |
565 | 67b915a5 | bellard | int AUD_write (void *in_buf, int size) |
566 | 67b915a5 | bellard | { |
567 | 67b915a5 | bellard | return 0; |
568 | 67b915a5 | bellard | } |
569 | 67b915a5 | bellard | |
570 | 67b915a5 | bellard | void AUD_reset (int rfreq, int rnchannels, audfmt_e rfmt) |
571 | 67b915a5 | bellard | { |
572 | 67b915a5 | bellard | } |
573 | 67b915a5 | bellard | |
574 | 67b915a5 | bellard | void AUD_adjust_estimate (int _leftover) |
575 | 67b915a5 | bellard | { |
576 | 67b915a5 | bellard | } |
577 | 67b915a5 | bellard | |
578 | 67b915a5 | bellard | int AUD_get_free (void) |
579 | 67b915a5 | bellard | { |
580 | 67b915a5 | bellard | return 0; |
581 | 67b915a5 | bellard | } |
582 | 67b915a5 | bellard | |
583 | 67b915a5 | bellard | int AUD_get_live (void) |
584 | 67b915a5 | bellard | { |
585 | 67b915a5 | bellard | return 0; |
586 | 67b915a5 | bellard | } |
587 | 67b915a5 | bellard | |
588 | 67b915a5 | bellard | int AUD_get_buffer_size (void) |
589 | 67b915a5 | bellard | { |
590 | 67b915a5 | bellard | return 0; |
591 | 67b915a5 | bellard | } |
592 | 67b915a5 | bellard | |
593 | 67b915a5 | bellard | void AUD_init (void) |
594 | 67b915a5 | bellard | { |
595 | 67b915a5 | bellard | } |
596 | 67b915a5 | bellard | |
597 | 67b915a5 | bellard | #endif |