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