root / oss.c @ d64477af
History | View | Annotate | Download (12 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 | 27503323 | bellard | #include <fcntl.h> |
28 | 27503323 | bellard | #include <errno.h> |
29 | 27503323 | bellard | #include <stdio.h> |
30 | 27503323 | bellard | #include <unistd.h> |
31 | 27503323 | bellard | #include <string.h> |
32 | 27503323 | bellard | #include <stdlib.h> |
33 | 27503323 | bellard | #include <limits.h> |
34 | 27503323 | bellard | #include <inttypes.h> |
35 | 27503323 | bellard | #include <sys/types.h> |
36 | 27503323 | bellard | #include <sys/ioctl.h> |
37 | 27503323 | bellard | #include <sys/soundcard.h> |
38 | 27503323 | bellard | |
39 | 27503323 | bellard | |
40 | 27503323 | bellard | /* http://www.df.lth.se/~john_e/gems/gem002d.html */
|
41 | 27503323 | bellard | /* http://www.multi-platforms.com/Tips/PopCount.htm */
|
42 | 27503323 | bellard | static inline uint32_t popcount (uint32_t u) |
43 | 27503323 | bellard | { |
44 | 27503323 | bellard | u = ((u&0x55555555) + ((u>>1)&0x55555555)); |
45 | 27503323 | bellard | u = ((u&0x33333333) + ((u>>2)&0x33333333)); |
46 | 27503323 | bellard | u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f)); |
47 | 27503323 | bellard | u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff)); |
48 | 27503323 | bellard | u = ( u&0x0000ffff) + (u>>16); |
49 | 27503323 | bellard | return u;
|
50 | 27503323 | bellard | } |
51 | 27503323 | bellard | |
52 | 27503323 | bellard | static inline uint32_t lsbindex (uint32_t u) |
53 | 27503323 | bellard | { |
54 | 27503323 | bellard | return popcount ((u&-u)-1); |
55 | 27503323 | bellard | } |
56 | 27503323 | bellard | |
57 | 27503323 | bellard | #define MIN(a, b) ((a)>(b)?(b):(a))
|
58 | 27503323 | bellard | #define MAX(a, b) ((a)<(b)?(b):(a))
|
59 | 27503323 | bellard | |
60 | 27503323 | bellard | #define DEREF(x) (void)x |
61 | 27503323 | bellard | #define log(...) fprintf (stderr, "oss: " __VA_ARGS__) |
62 | 27503323 | bellard | #define ERRFail(...) do { \ |
63 | 27503323 | bellard | int _errno = errno; \
|
64 | 27503323 | bellard | fprintf (stderr, "oss: " __VA_ARGS__); \
|
65 | 27503323 | bellard | fprintf (stderr, "system error: %s\n", strerror (_errno)); \
|
66 | 27503323 | bellard | abort (); \ |
67 | 27503323 | bellard | } while (0) |
68 | 27503323 | bellard | #define Fail(...) do { \ |
69 | 27503323 | bellard | fprintf (stderr, "oss: " __VA_ARGS__); \
|
70 | 27503323 | bellard | fprintf (stderr, "\n"); \
|
71 | 27503323 | bellard | abort (); \ |
72 | 27503323 | bellard | } while (0) |
73 | 27503323 | bellard | |
74 | 27503323 | bellard | #ifdef DEBUG_OSS
|
75 | 27503323 | bellard | #define lwarn(...) fprintf (stderr, "oss: " __VA_ARGS__) |
76 | 27503323 | bellard | #define linfo(...) fprintf (stderr, "oss: " __VA_ARGS__) |
77 | 27503323 | bellard | #define ldebug(...) fprintf (stderr, "oss: " __VA_ARGS__) |
78 | 27503323 | bellard | #else
|
79 | 27503323 | bellard | #define lwarn(...)
|
80 | 27503323 | bellard | #define linfo(...)
|
81 | 27503323 | bellard | #define ldebug(...)
|
82 | 27503323 | bellard | #endif
|
83 | 27503323 | bellard | |
84 | 27503323 | bellard | |
85 | 27503323 | bellard | #define IOCTL(args) do { \ |
86 | 27503323 | bellard | int ret = ioctl args; \
|
87 | 27503323 | bellard | if (-1 == ret) { \ |
88 | 27503323 | bellard | ERRFail (#args); \
|
89 | 27503323 | bellard | } \ |
90 | 27503323 | bellard | ldebug ("ioctl " #args " = %d\n", ret); \ |
91 | 27503323 | bellard | } while (0) |
92 | 27503323 | bellard | |
93 | 27503323 | bellard | static int audio_fd = -1; |
94 | 27503323 | bellard | static int freq; |
95 | 27503323 | bellard | static int conf_nfrags = 4; |
96 | 27503323 | bellard | static int conf_fragsize; |
97 | 27503323 | bellard | static int nfrags; |
98 | 27503323 | bellard | static int fragsize; |
99 | 27503323 | bellard | static int bufsize; |
100 | 27503323 | bellard | static int nchannels; |
101 | 27503323 | bellard | static int fmt; |
102 | 27503323 | bellard | static int rpos; |
103 | 27503323 | bellard | static int wpos; |
104 | 27503323 | bellard | static int atom; |
105 | 27503323 | bellard | static int live; |
106 | 27503323 | bellard | static int leftover; |
107 | 27503323 | bellard | static int bytes_per_second; |
108 | 27503323 | bellard | static void *buf; |
109 | 27503323 | bellard | static enum {DONT, DSP, TID} estimate = TID; |
110 | 27503323 | bellard | |
111 | 27503323 | bellard | static void (*copy_fn)(void *, void *, int); |
112 | 27503323 | bellard | |
113 | 27503323 | bellard | static void copy_no_conversion (void *dst, void *src, int size) |
114 | 27503323 | bellard | { |
115 | 27503323 | bellard | memcpy (dst, src, size); |
116 | 27503323 | bellard | } |
117 | 27503323 | bellard | |
118 | 27503323 | bellard | static void copy_u16_to_s16 (void *dst, void *src, int size) |
119 | 27503323 | bellard | { |
120 | 27503323 | bellard | int i;
|
121 | 27503323 | bellard | uint16_t *out, *in; |
122 | 27503323 | bellard | |
123 | 27503323 | bellard | out = dst; |
124 | 27503323 | bellard | in = src; |
125 | 27503323 | bellard | |
126 | 27503323 | bellard | for (i = 0; i < size / 2; i++) { |
127 | 27503323 | bellard | out[i] = in[i] + 0x8000;
|
128 | 27503323 | bellard | } |
129 | 27503323 | bellard | } |
130 | 27503323 | bellard | |
131 | 27503323 | bellard | static void pab (struct audio_buf_info *abinfo) |
132 | 27503323 | bellard | { |
133 | 27503323 | bellard | DEREF (abinfo); |
134 | 27503323 | bellard | |
135 | 27503323 | bellard | ldebug ("fragments %d, fragstotal %d, fragsize %d, bytes %d\n"
|
136 | 27503323 | bellard | "rpos %d, wpos %d, live %d\n",
|
137 | 27503323 | bellard | abinfo->fragments, |
138 | 27503323 | bellard | abinfo->fragstotal, |
139 | 27503323 | bellard | abinfo->fragsize, |
140 | 27503323 | bellard | abinfo->bytes, |
141 | 27503323 | bellard | rpos, wpos, live); |
142 | 27503323 | bellard | } |
143 | 27503323 | bellard | |
144 | 27503323 | bellard | void AUD_reset (int rfreq, int rnchannels, audfmt_e rfmt) |
145 | 27503323 | bellard | { |
146 | 27503323 | bellard | int fmt_;
|
147 | 27503323 | bellard | int bits16;
|
148 | 27503323 | bellard | |
149 | 27503323 | bellard | if (-1 == audio_fd) { |
150 | 27503323 | bellard | AUD_open (rfreq, rnchannels, rfmt); |
151 | 27503323 | bellard | return;
|
152 | 27503323 | bellard | } |
153 | 27503323 | bellard | |
154 | 27503323 | bellard | switch (rfmt) {
|
155 | 27503323 | bellard | case AUD_FMT_U8:
|
156 | 27503323 | bellard | bits16 = 0;
|
157 | 27503323 | bellard | fmt_ = AFMT_U8; |
158 | 27503323 | bellard | copy_fn = copy_no_conversion; |
159 | 27503323 | bellard | atom = 1;
|
160 | 27503323 | bellard | break;
|
161 | 27503323 | bellard | |
162 | 27503323 | bellard | case AUD_FMT_S8:
|
163 | 27503323 | bellard | Fail ("can not play 8bit signed");
|
164 | 27503323 | bellard | |
165 | 27503323 | bellard | case AUD_FMT_S16:
|
166 | 27503323 | bellard | bits16 = 1;
|
167 | 27503323 | bellard | fmt_ = AFMT_S16_LE; |
168 | 27503323 | bellard | copy_fn = copy_no_conversion; |
169 | 27503323 | bellard | atom = 2;
|
170 | 27503323 | bellard | break;
|
171 | 27503323 | bellard | |
172 | 27503323 | bellard | case AUD_FMT_U16:
|
173 | 27503323 | bellard | bits16 = 1;
|
174 | 27503323 | bellard | fmt_ = AFMT_S16_LE; |
175 | 27503323 | bellard | copy_fn = copy_u16_to_s16; |
176 | 27503323 | bellard | atom = 2;
|
177 | 27503323 | bellard | break;
|
178 | 27503323 | bellard | |
179 | 27503323 | bellard | default:
|
180 | 27503323 | bellard | abort (); |
181 | 27503323 | bellard | } |
182 | 27503323 | bellard | |
183 | 27503323 | bellard | if ((fmt_ == fmt) && (bits16 + 1 == nchannels) && (rfreq == freq)) |
184 | 27503323 | bellard | return;
|
185 | 27503323 | bellard | else {
|
186 | 27503323 | bellard | AUD_open (rfreq, rnchannels, rfmt); |
187 | 27503323 | bellard | } |
188 | 27503323 | bellard | } |
189 | 27503323 | bellard | |
190 | 27503323 | bellard | void AUD_open (int rfreq, int rnchannels, audfmt_e rfmt) |
191 | 27503323 | bellard | { |
192 | 27503323 | bellard | int fmt_;
|
193 | 27503323 | bellard | int mmmmssss;
|
194 | 27503323 | bellard | struct audio_buf_info abinfo;
|
195 | 27503323 | bellard | int _fmt;
|
196 | 27503323 | bellard | int _freq;
|
197 | 27503323 | bellard | int _nchannels;
|
198 | 27503323 | bellard | int bits16;
|
199 | 27503323 | bellard | |
200 | 27503323 | bellard | bits16 = 0;
|
201 | 27503323 | bellard | |
202 | 27503323 | bellard | switch (rfmt) {
|
203 | 27503323 | bellard | case AUD_FMT_U8:
|
204 | 27503323 | bellard | bits16 = 0;
|
205 | 27503323 | bellard | fmt_ = AFMT_U8; |
206 | 27503323 | bellard | copy_fn = copy_no_conversion; |
207 | 27503323 | bellard | atom = 1;
|
208 | 27503323 | bellard | break;
|
209 | 27503323 | bellard | |
210 | 27503323 | bellard | case AUD_FMT_S8:
|
211 | 27503323 | bellard | Fail ("can not play 8bit signed");
|
212 | 27503323 | bellard | |
213 | 27503323 | bellard | case AUD_FMT_S16:
|
214 | 27503323 | bellard | bits16 = 1;
|
215 | 27503323 | bellard | fmt_ = AFMT_S16_LE; |
216 | 27503323 | bellard | copy_fn = copy_no_conversion; |
217 | 27503323 | bellard | atom = 2;
|
218 | 27503323 | bellard | break;
|
219 | 27503323 | bellard | |
220 | 27503323 | bellard | case AUD_FMT_U16:
|
221 | 27503323 | bellard | bits16 = 1;
|
222 | 27503323 | bellard | fmt_ = AFMT_S16_LE; |
223 | 27503323 | bellard | copy_fn = copy_u16_to_s16; |
224 | 27503323 | bellard | atom = 2;
|
225 | 27503323 | bellard | break;
|
226 | 27503323 | bellard | |
227 | 27503323 | bellard | default:
|
228 | 27503323 | bellard | abort (); |
229 | 27503323 | bellard | } |
230 | 27503323 | bellard | |
231 | 27503323 | bellard | if (buf) {
|
232 | 27503323 | bellard | free (buf); |
233 | 27503323 | bellard | buf = 0;
|
234 | 27503323 | bellard | } |
235 | 27503323 | bellard | |
236 | 27503323 | bellard | if (-1 != audio_fd) |
237 | 27503323 | bellard | close (audio_fd); |
238 | 27503323 | bellard | |
239 | 27503323 | bellard | audio_fd = open ("/dev/dsp", O_WRONLY | O_NONBLOCK);
|
240 | 27503323 | bellard | if (-1 == audio_fd) { |
241 | 27503323 | bellard | ERRFail ("can not open /dev/dsp");
|
242 | 27503323 | bellard | } |
243 | 27503323 | bellard | |
244 | 27503323 | bellard | _fmt = fmt_; |
245 | 27503323 | bellard | _freq = rfreq; |
246 | 27503323 | bellard | _nchannels = rnchannels; |
247 | 27503323 | bellard | |
248 | 27503323 | bellard | IOCTL ((audio_fd, SNDCTL_DSP_RESET, 1));
|
249 | 27503323 | bellard | IOCTL ((audio_fd, SNDCTL_DSP_SAMPLESIZE, &_fmt)); |
250 | 27503323 | bellard | IOCTL ((audio_fd, SNDCTL_DSP_CHANNELS, &_nchannels)); |
251 | 27503323 | bellard | IOCTL ((audio_fd, SNDCTL_DSP_SPEED, &_freq)); |
252 | 27503323 | bellard | IOCTL ((audio_fd, SNDCTL_DSP_NONBLOCK)); |
253 | 27503323 | bellard | |
254 | 27503323 | bellard | /* from oss.pdf:
|
255 | 27503323 | bellard | |
256 | 27503323 | bellard | The argument to this call is an integer encoded as 0xMMMMSSSS (in
|
257 | 27503323 | bellard | hex). The 16 least significant bits determine the fragment
|
258 | 27503323 | bellard | size. The size is 2^SSSS. For examp le SSSS=0008 gives fragment
|
259 | 27503323 | bellard | size of 256 bytes (2^8). The minimum is 16 bytes (SSSS=4) and the
|
260 | 27503323 | bellard | maximum is total_buffer_size/2. Some devices or processor
|
261 | 27503323 | bellard | architectures may require larger fragments - in this case the
|
262 | 27503323 | bellard | requested fragment size is automatically increased.
|
263 | 27503323 | bellard | |
264 | 27503323 | bellard | So ahem... 4096 = 2^12, and grand total 0x0004000c
|
265 | 27503323 | bellard | */
|
266 | 27503323 | bellard | |
267 | 27503323 | bellard | mmmmssss = (conf_nfrags << 16) | conf_fragsize;
|
268 | 27503323 | bellard | IOCTL ((audio_fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)); |
269 | 27503323 | bellard | |
270 | 27503323 | bellard | linfo ("_fmt = %d, fmt = %d\n"
|
271 | 27503323 | bellard | "_channels = %d, rnchannels = %d\n"
|
272 | 27503323 | bellard | "_freq = %d, freq = %d\n",
|
273 | 27503323 | bellard | _fmt, fmt_, |
274 | 27503323 | bellard | _nchannels, rnchannels, |
275 | 27503323 | bellard | _freq, rfreq); |
276 | 27503323 | bellard | |
277 | 27503323 | bellard | if (_fmt != fmt_) {
|
278 | 27503323 | bellard | Fail ("format %d != %d", _fmt, fmt_);
|
279 | 27503323 | bellard | } |
280 | 27503323 | bellard | |
281 | 27503323 | bellard | if (_nchannels != rnchannels) {
|
282 | 27503323 | bellard | Fail ("channels %d != %d", _nchannels, rnchannels);
|
283 | 27503323 | bellard | } |
284 | 27503323 | bellard | |
285 | 27503323 | bellard | if (_freq != rfreq) {
|
286 | 27503323 | bellard | Fail ("freq %d != %d", _freq, rfreq);
|
287 | 27503323 | bellard | } |
288 | 27503323 | bellard | |
289 | 27503323 | bellard | IOCTL ((audio_fd, SNDCTL_DSP_GETOSPACE, &abinfo)); |
290 | 27503323 | bellard | |
291 | 27503323 | bellard | nfrags = abinfo.fragstotal; |
292 | 27503323 | bellard | fragsize = abinfo.fragsize; |
293 | 27503323 | bellard | freq = _freq; |
294 | 27503323 | bellard | fmt = _fmt; |
295 | 27503323 | bellard | nchannels = rnchannels; |
296 | 27503323 | bellard | atom <<= nchannels >> 1;
|
297 | 27503323 | bellard | bufsize = nfrags * fragsize; |
298 | 27503323 | bellard | |
299 | 27503323 | bellard | bytes_per_second = (freq << (nchannels >> 1)) << bits16;
|
300 | 27503323 | bellard | |
301 | 27503323 | bellard | linfo ("bytes per second %d\n", bytes_per_second);
|
302 | 27503323 | bellard | |
303 | 27503323 | bellard | linfo ("fragments %d, fragstotal %d, fragsize %d, bytes %d, bufsize %d\n",
|
304 | 27503323 | bellard | abinfo.fragments, |
305 | 27503323 | bellard | abinfo.fragstotal, |
306 | 27503323 | bellard | abinfo.fragsize, |
307 | 27503323 | bellard | abinfo.bytes, |
308 | 27503323 | bellard | bufsize); |
309 | 27503323 | bellard | |
310 | 27503323 | bellard | if (NULL == buf) { |
311 | 27503323 | bellard | buf = malloc (bufsize); |
312 | 27503323 | bellard | if (NULL == buf) { |
313 | 27503323 | bellard | abort (); |
314 | 27503323 | bellard | } |
315 | 27503323 | bellard | } |
316 | 27503323 | bellard | |
317 | 27503323 | bellard | rpos = 0;
|
318 | 27503323 | bellard | wpos = 0;
|
319 | 27503323 | bellard | live = 0;
|
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 | 27503323 | bellard | to_copy = MIN (bufsize - live, size); |
328 | 27503323 | bellard | |
329 | 27503323 | bellard | temp = to_copy; |
330 | 27503323 | bellard | |
331 | 27503323 | bellard | in = in_buf; |
332 | 27503323 | bellard | out = buf; |
333 | 27503323 | bellard | |
334 | 27503323 | bellard | while (temp) {
|
335 | 27503323 | bellard | int copy;
|
336 | 27503323 | bellard | |
337 | 27503323 | bellard | copy = MIN (temp, bufsize - wpos); |
338 | 27503323 | bellard | copy_fn (out + wpos, in, copy); |
339 | 27503323 | bellard | |
340 | 27503323 | bellard | wpos += copy; |
341 | 27503323 | bellard | if (wpos == bufsize) {
|
342 | 27503323 | bellard | wpos = 0;
|
343 | 27503323 | bellard | } |
344 | 27503323 | bellard | |
345 | 27503323 | bellard | temp -= copy; |
346 | 27503323 | bellard | in += copy; |
347 | 27503323 | bellard | 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 | 27503323 | bellard | if (0 == live) |
360 | 27503323 | bellard | return;
|
361 | 27503323 | bellard | |
362 | 27503323 | bellard | res = ioctl (audio_fd, SNDCTL_DSP_GETOSPACE, &abinfo); |
363 | 27503323 | bellard | |
364 | 27503323 | bellard | if (-1 == res) { |
365 | 27503323 | bellard | int err;
|
366 | 27503323 | bellard | |
367 | 27503323 | bellard | err = errno; |
368 | 27503323 | bellard | lwarn ("SNDCTL_DSP_GETOSPACE failed with %s\n", strerror (err));
|
369 | 27503323 | bellard | } |
370 | 27503323 | bellard | |
371 | 27503323 | bellard | bytes = abinfo.bytes; |
372 | 27503323 | bellard | bytes = MIN (live, bytes); |
373 | 27503323 | bellard | #if 0
|
374 | 27503323 | bellard | bytes = (bytes / fragsize) * fragsize;
|
375 | 27503323 | bellard | #endif
|
376 | 27503323 | bellard | |
377 | 27503323 | bellard | while (bytes) {
|
378 | 27503323 | bellard | int left, play, written;
|
379 | 27503323 | bellard | |
380 | 27503323 | bellard | left = bufsize - rpos; |
381 | 27503323 | bellard | play = MIN (left, bytes); |
382 | 27503323 | bellard | written = write (audio_fd, (void *) ((uint32_t) buf + rpos), play);
|
383 | 27503323 | bellard | |
384 | 27503323 | bellard | if (-1 == written) { |
385 | 27503323 | bellard | if (EAGAIN == errno || EINTR == errno) {
|
386 | 27503323 | bellard | return;
|
387 | 27503323 | bellard | } |
388 | 27503323 | bellard | else {
|
389 | 27503323 | bellard | ERRFail ("write audio");
|
390 | 27503323 | bellard | } |
391 | 27503323 | bellard | } |
392 | 27503323 | bellard | |
393 | 27503323 | bellard | play = written; |
394 | 27503323 | bellard | live -= play; |
395 | 27503323 | bellard | rpos += play; |
396 | 27503323 | bellard | bytes -= play; |
397 | 27503323 | bellard | |
398 | 27503323 | bellard | if (rpos == bufsize) {
|
399 | 27503323 | bellard | rpos = 0;
|
400 | 27503323 | bellard | } |
401 | 27503323 | bellard | } |
402 | 27503323 | bellard | } |
403 | 27503323 | bellard | |
404 | 27503323 | bellard | static int get_dsp_bytes (void) |
405 | 27503323 | bellard | { |
406 | 27503323 | bellard | int res;
|
407 | 27503323 | bellard | struct count_info info;
|
408 | 27503323 | bellard | |
409 | 27503323 | bellard | res = ioctl (audio_fd, SNDCTL_DSP_GETOPTR, &info); |
410 | 27503323 | bellard | if (-1 == res) { |
411 | 27503323 | bellard | int err;
|
412 | 27503323 | bellard | |
413 | 27503323 | bellard | err = errno; |
414 | 27503323 | bellard | lwarn ("SNDCTL_DSP_GETOPTR failed with %s\n", strerror (err));
|
415 | 27503323 | bellard | return -1; |
416 | 27503323 | bellard | } |
417 | 27503323 | bellard | else {
|
418 | 27503323 | bellard | ldebug ("bytes %d\n", info.bytes);
|
419 | 27503323 | bellard | return info.bytes;
|
420 | 27503323 | bellard | } |
421 | 27503323 | bellard | } |
422 | 27503323 | bellard | |
423 | 27503323 | bellard | void AUD_adjust_estimate (int _leftover) |
424 | 27503323 | bellard | { |
425 | 27503323 | bellard | leftover = _leftover; |
426 | 27503323 | bellard | } |
427 | 27503323 | bellard | |
428 | 27503323 | bellard | int AUD_get_free (void) |
429 | 27503323 | bellard | { |
430 | 27503323 | bellard | int free, elapsed;
|
431 | 27503323 | bellard | |
432 | 27503323 | bellard | free = bufsize - live; |
433 | 27503323 | bellard | |
434 | 27503323 | bellard | if (0 == free) |
435 | 27503323 | bellard | return 0; |
436 | 27503323 | bellard | |
437 | 27503323 | bellard | elapsed = free; |
438 | 27503323 | bellard | switch (estimate) {
|
439 | 27503323 | bellard | case DONT:
|
440 | 27503323 | bellard | break;
|
441 | 27503323 | bellard | |
442 | 27503323 | bellard | case DSP:
|
443 | 27503323 | bellard | { |
444 | 27503323 | bellard | static int old_bytes; |
445 | 27503323 | bellard | int bytes;
|
446 | 27503323 | bellard | |
447 | 27503323 | bellard | bytes = get_dsp_bytes (); |
448 | 27503323 | bellard | if (bytes <= 0) |
449 | 27503323 | bellard | return free;
|
450 | 27503323 | bellard | |
451 | 27503323 | bellard | elapsed = bytes - old_bytes; |
452 | 27503323 | bellard | old_bytes = bytes; |
453 | 27503323 | bellard | ldebug ("dsp elapsed %d bytes\n", elapsed);
|
454 | 27503323 | bellard | break;
|
455 | 27503323 | bellard | } |
456 | 27503323 | bellard | |
457 | 27503323 | bellard | case TID:
|
458 | 27503323 | bellard | { |
459 | 27503323 | bellard | static uint64_t old_ticks;
|
460 | 27503323 | bellard | uint64_t ticks, delta; |
461 | 27503323 | bellard | uint64_t ua_elapsed; |
462 | 27503323 | bellard | uint64_t al_elapsed; |
463 | 27503323 | bellard | |
464 | 8a7ddc38 | bellard | ticks = qemu_get_clock(rt_clock); |
465 | 27503323 | bellard | delta = ticks - old_ticks; |
466 | 27503323 | bellard | old_ticks = ticks; |
467 | 27503323 | bellard | |
468 | 8a7ddc38 | bellard | ua_elapsed = (delta * bytes_per_second) / 1000;
|
469 | 27503323 | bellard | al_elapsed = ua_elapsed & ~3ULL;
|
470 | 27503323 | bellard | |
471 | 27503323 | bellard | ldebug ("tid elapsed %llu bytes\n", ua_elapsed);
|
472 | 27503323 | bellard | |
473 | 27503323 | bellard | if (al_elapsed > (uint64_t) INT_MAX)
|
474 | 27503323 | bellard | elapsed = INT_MAX; |
475 | 27503323 | bellard | else
|
476 | 27503323 | bellard | elapsed = al_elapsed; |
477 | 27503323 | bellard | |
478 | 27503323 | bellard | elapsed += leftover; |
479 | 27503323 | bellard | } |
480 | 27503323 | bellard | } |
481 | 27503323 | bellard | |
482 | 27503323 | bellard | if (elapsed > free) {
|
483 | 27503323 | bellard | lwarn ("audio can not keep up elapsed %d free %d\n", elapsed, free);
|
484 | 27503323 | bellard | return free;
|
485 | 27503323 | bellard | } |
486 | 27503323 | bellard | else {
|
487 | 27503323 | bellard | return elapsed;
|
488 | 27503323 | bellard | } |
489 | 27503323 | bellard | } |
490 | 27503323 | bellard | |
491 | 27503323 | bellard | int AUD_get_live (void) |
492 | 27503323 | bellard | { |
493 | 27503323 | bellard | return live;
|
494 | 27503323 | bellard | } |
495 | 27503323 | bellard | |
496 | 27503323 | bellard | int AUD_get_buffer_size (void) |
497 | 27503323 | bellard | { |
498 | 27503323 | bellard | return bufsize;
|
499 | 27503323 | bellard | } |
500 | 27503323 | bellard | |
501 | 27503323 | bellard | void AUD_init (void) |
502 | 27503323 | bellard | { |
503 | 27503323 | bellard | int fsp;
|
504 | 27503323 | bellard | int _fragsize = 4096; |
505 | 27503323 | bellard | |
506 | 27503323 | bellard | DEREF (pab); |
507 | 27503323 | bellard | |
508 | 27503323 | bellard | fsp = _fragsize; |
509 | 27503323 | bellard | if (0 != (fsp & (fsp - 1))) { |
510 | 27503323 | bellard | Fail ("fragment size %d is not power of 2", fsp);
|
511 | 27503323 | bellard | } |
512 | 27503323 | bellard | |
513 | 27503323 | bellard | conf_fragsize = lsbindex (fsp); |
514 | 27503323 | bellard | } |
515 | 67b915a5 | bellard | |
516 | 67b915a5 | bellard | #else
|
517 | 67b915a5 | bellard | |
518 | 67b915a5 | bellard | void AUD_run (void) |
519 | 67b915a5 | bellard | { |
520 | 67b915a5 | bellard | } |
521 | 67b915a5 | bellard | |
522 | 67b915a5 | bellard | int AUD_write (void *in_buf, int size) |
523 | 67b915a5 | bellard | { |
524 | 67b915a5 | bellard | return 0; |
525 | 67b915a5 | bellard | } |
526 | 67b915a5 | bellard | |
527 | 67b915a5 | bellard | void AUD_reset (int rfreq, int rnchannels, audfmt_e rfmt) |
528 | 67b915a5 | bellard | { |
529 | 67b915a5 | bellard | } |
530 | 67b915a5 | bellard | |
531 | 67b915a5 | bellard | void AUD_adjust_estimate (int _leftover) |
532 | 67b915a5 | bellard | { |
533 | 67b915a5 | bellard | } |
534 | 67b915a5 | bellard | |
535 | 67b915a5 | bellard | int AUD_get_free (void) |
536 | 67b915a5 | bellard | { |
537 | 67b915a5 | bellard | return 0; |
538 | 67b915a5 | bellard | } |
539 | 67b915a5 | bellard | |
540 | 67b915a5 | bellard | int AUD_get_live (void) |
541 | 67b915a5 | bellard | { |
542 | 67b915a5 | bellard | return 0; |
543 | 67b915a5 | bellard | } |
544 | 67b915a5 | bellard | |
545 | 67b915a5 | bellard | int AUD_get_buffer_size (void) |
546 | 67b915a5 | bellard | { |
547 | 67b915a5 | bellard | return 0; |
548 | 67b915a5 | bellard | } |
549 | 67b915a5 | bellard | |
550 | 67b915a5 | bellard | void AUD_init (void) |
551 | 67b915a5 | bellard | { |
552 | 67b915a5 | bellard | } |
553 | 67b915a5 | bellard | |
554 | 67b915a5 | bellard | #endif |