Mercurial > audlegacy
annotate Plugins/Output/OSS/audio.c @ 701:d539e5c5f730 trunk
[svn] Fixes of the remaining GCC 4.1 warnings from external contributor Diego "Flameeyes" Petteno (Gentoo).
author | chainsaw |
---|---|
date | Sun, 26 Feb 2006 13:08:35 -0800 |
parents | 55dc40ff1aff |
children | 9783edaae2b5 |
rev | line source |
---|---|
61 | 1 /* BMP - Cross-platform multimedia player |
2 * Copyright (C) 2003-2004 BMP development team. | |
3 * | |
4 * Based on XMMS: | |
5 * Copyright (C) 1998-2003 XMMS development team. | |
6 * | |
7 * This program is free software; you can redistribute it and/or modify | |
8 * it under the terms of the GNU General Public License as published by | |
9 * the Free Software Foundation; either version 2 of the License, or | |
10 * (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 * GNU General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU General Public License | |
18 * along with this program; if not, write to the Free Software | |
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
20 */ | |
21 | |
22 #include <glib.h> | |
23 #include <libaudacious/util.h> | |
24 #include <string.h> | |
25 | |
26 #include <unistd.h> | |
27 #include <fcntl.h> | |
28 #include <errno.h> | |
29 #include <sys/ioctl.h> | |
30 #include <sys/time.h> | |
31 | |
32 #include "OSS.h" | |
33 | |
34 | |
35 #define NFRAGS 32 | |
36 | |
37 static gint fd = 0; | |
38 static char *buffer; | |
39 static gboolean going, prebuffer, paused, unpause, do_pause, remove_prebuffer; | |
701
d539e5c5f730
[svn] Fixes of the remaining GCC 4.1 warnings from external contributor Diego "Flameeyes" Petteno (Gentoo).
chainsaw
parents:
517
diff
changeset
|
40 static gint buffer_size, prebuffer_size, blk_size; |
61 | 41 static gint rd_index = 0, wr_index = 0; |
42 static gint output_time_offset = 0; | |
701
d539e5c5f730
[svn] Fixes of the remaining GCC 4.1 warnings from external contributor Diego "Flameeyes" Petteno (Gentoo).
chainsaw
parents:
517
diff
changeset
|
43 static guint64 written = 0, output_bytes = 0, device_buffer_used; |
61 | 44 static gint flush; |
45 static gint fragsize, device_buffer_size; | |
46 static gchar *device_name; | |
47 static GThread *buffer_thread; | |
48 static gboolean realtime, select_works; | |
49 | |
50 static int (*oss_convert_func) (void **data, int length); | |
51 static int (*oss_stereo_convert_func) (void **data, int length, int fmt); | |
52 | |
53 struct format_info { | |
54 union { | |
55 AFormat xmms; | |
56 int oss; | |
57 } format; | |
58 int frequency; | |
59 int channels; | |
60 int bps; | |
61 }; | |
62 | |
63 | |
64 /* | |
65 * The format of the data from the input plugin | |
66 * This will never change during a song. | |
67 */ | |
68 struct format_info input; | |
69 | |
70 /* | |
71 * The format we get from the effect plugin. | |
72 * This will be different from input if the effect plugin does | |
73 * some kind of format conversion. | |
74 */ | |
75 struct format_info effect; | |
76 | |
77 /* | |
78 * The format of the data we actually send to the soundcard. | |
79 * This might be different from effect if we need to resample or do | |
80 * some other format conversion. | |
81 */ | |
82 struct format_info output; | |
83 | |
84 | |
85 static void | |
86 oss_calc_device_buffer_used(void) | |
87 { | |
88 audio_buf_info buf_info; | |
89 if (paused) | |
90 device_buffer_used = 0; | |
91 else if (!ioctl(fd, SNDCTL_DSP_GETOSPACE, &buf_info)) | |
92 device_buffer_used = | |
93 (buf_info.fragstotal * buf_info.fragsize) - buf_info.bytes; | |
94 } | |
95 | |
96 | |
97 static gint oss_downsample(gpointer ob, guint length, guint speed, | |
98 guint espeed); | |
99 | |
100 static int | |
101 oss_calc_bitrate(int oss_fmt, int rate, int channels) | |
102 { | |
103 int bitrate = rate * channels; | |
104 | |
105 if (oss_fmt == AFMT_U16_BE || oss_fmt == AFMT_U16_LE || | |
106 oss_fmt == AFMT_S16_BE || oss_fmt == AFMT_S16_LE) | |
107 bitrate *= 2; | |
108 | |
109 return bitrate; | |
110 } | |
111 | |
112 static int | |
113 oss_get_format(AFormat fmt) | |
114 { | |
115 int format = 0; | |
116 | |
117 switch (fmt) { | |
118 case FMT_U8: | |
119 format = AFMT_U8; | |
120 break; | |
121 case FMT_S8: | |
122 format = AFMT_S8; | |
123 break; | |
124 case FMT_U16_LE: | |
125 format = AFMT_U16_LE; | |
126 break; | |
127 case FMT_U16_BE: | |
128 format = AFMT_U16_BE; | |
129 break; | |
130 case FMT_U16_NE: | |
131 #if (G_BYTE_ORDER == G_BIG_ENDIAN) | |
132 format = AFMT_U16_BE; | |
133 #else | |
134 format = AFMT_U16_LE; | |
135 #endif | |
136 break; | |
137 case FMT_S16_LE: | |
138 format = AFMT_S16_LE; | |
139 break; | |
140 case FMT_S16_BE: | |
141 format = AFMT_S16_BE; | |
142 break; | |
143 case FMT_S16_NE: | |
144 #if (G_BYTE_ORDER == G_BIG_ENDIAN) | |
145 format = AFMT_S16_BE; | |
146 #else | |
147 format = AFMT_S16_LE; | |
148 #endif | |
149 break; | |
150 } | |
151 | |
152 return format; | |
153 } | |
154 | |
155 static void | |
156 oss_setup_format(AFormat fmt, int rate, int nch) | |
157 { | |
158 effect.format.xmms = fmt; | |
159 effect.frequency = rate; | |
160 effect.channels = nch; | |
161 effect.bps = oss_calc_bitrate(oss_get_format(fmt), rate, nch); | |
162 | |
163 output.format.oss = oss_get_format(fmt); | |
164 output.frequency = rate; | |
165 output.channels = nch; | |
166 | |
167 | |
168 fragsize = 0; | |
169 while ((1L << fragsize) < effect.bps / 25) | |
170 fragsize++; | |
171 fragsize--; | |
172 | |
173 device_buffer_size = ((1L << fragsize) * (NFRAGS + 1)); | |
174 | |
175 oss_set_audio_params(); | |
176 | |
177 output.bps = oss_calc_bitrate(output.format.oss, output.frequency, | |
178 output.channels); | |
179 } | |
180 | |
181 | |
182 gint | |
183 oss_get_written_time(void) | |
184 { | |
185 if (!going) | |
186 return 0; | |
187 return (written * 1000) / effect.bps; | |
188 } | |
189 | |
190 gint | |
191 oss_get_output_time(void) | |
192 { | |
193 guint64 bytes; | |
194 | |
195 if (!fd || !going) | |
196 return 0; | |
197 | |
198 if (realtime) | |
199 oss_calc_device_buffer_used(); | |
200 bytes = output_bytes < device_buffer_used ? | |
201 0 : output_bytes - device_buffer_used; | |
202 | |
203 return output_time_offset + ((bytes * 1000) / output.bps); | |
204 } | |
205 | |
206 static int | |
207 oss_used(void) | |
208 { | |
209 if (realtime) | |
210 return 0; | |
211 else { | |
212 if (wr_index >= rd_index) | |
213 return wr_index - rd_index; | |
214 return buffer_size - (rd_index - wr_index); | |
215 } | |
216 } | |
217 | |
218 gint | |
219 oss_playing(void) | |
220 { | |
221 if (!going) | |
222 return 0; | |
223 if (realtime) | |
224 oss_calc_device_buffer_used(); | |
225 if (!oss_used() && (device_buffer_used - (3 * blk_size)) <= 0) | |
226 return FALSE; | |
227 | |
228 return TRUE; | |
229 } | |
230 | |
231 gint | |
232 oss_free(void) | |
233 { | |
234 if (!realtime) { | |
235 if (remove_prebuffer && prebuffer) { | |
236 prebuffer = FALSE; | |
237 remove_prebuffer = FALSE; | |
238 } | |
239 if (prebuffer) | |
240 remove_prebuffer = TRUE; | |
241 | |
242 if (rd_index > wr_index) | |
243 return (rd_index - wr_index) - device_buffer_size - 1; | |
244 return (buffer_size - (wr_index - rd_index)) - device_buffer_size - 1; | |
245 } | |
246 else if (paused) | |
247 return 0; | |
248 else | |
249 return 1000000; | |
250 } | |
251 | |
252 static inline ssize_t | |
253 write_all(int fd, const void *buf, size_t count) | |
254 { | |
701
d539e5c5f730
[svn] Fixes of the remaining GCC 4.1 warnings from external contributor Diego "Flameeyes" Petteno (Gentoo).
chainsaw
parents:
517
diff
changeset
|
255 size_t done = 0; |
61 | 256 do { |
382
a9c7793de60c
[svn] fix audio corruption when doing a short write.
nenolod
parents:
61
diff
changeset
|
257 ssize_t n = write(fd, (gchar *) buf + done, count - done); |
61 | 258 if (n == -1) { |
259 if (errno == EINTR) | |
260 continue; | |
261 else | |
262 break; | |
263 } | |
264 done += n; | |
265 } while (count > done); | |
266 | |
267 return done; | |
268 } | |
269 | |
270 static void | |
271 oss_write_audio(gpointer data, int length) | |
272 { | |
273 | |
274 audio_buf_info abuf_info; | |
275 AFormat new_format; | |
276 int new_frequency, new_channels; | |
277 EffectPlugin *ep; | |
278 | |
279 new_format = input.format.xmms; | |
280 new_frequency = input.frequency; | |
281 new_channels = input.channels; | |
282 | |
283 | |
284 ep = get_current_effect_plugin(); | |
285 if (effects_enabled() && ep && ep->query_format) { | |
286 ep->query_format(&new_format, &new_frequency, &new_channels); | |
287 } | |
288 | |
289 if (new_format != effect.format.xmms || | |
290 new_frequency != effect.frequency || | |
291 new_channels != effect.channels) { | |
292 output_time_offset += (output_bytes * 1000) / output.bps; | |
293 output_bytes = 0; | |
294 close(fd); | |
295 fd = open(device_name, O_WRONLY); | |
296 oss_setup_format(new_format, new_frequency, new_channels); | |
297 } | |
298 if (effects_enabled() && ep && ep->mod_samples) | |
299 length = ep->mod_samples(&data, length, | |
300 input.format.xmms, | |
301 input.frequency, input.channels); | |
302 if (realtime && !ioctl(fd, SNDCTL_DSP_GETOSPACE, &abuf_info)) { | |
303 while (abuf_info.bytes < length) { | |
304 xmms_usleep(10000); | |
305 if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &abuf_info)) | |
306 break; | |
307 } | |
308 } | |
309 | |
310 if (oss_convert_func != NULL) | |
311 length = oss_convert_func(&data, length); | |
312 | |
313 if (oss_stereo_convert_func != NULL) | |
314 length = oss_stereo_convert_func(&data, length, output.format.oss); | |
315 | |
316 if (effect.frequency == output.frequency) | |
317 output_bytes += write_all(fd, data, length); | |
318 else | |
319 output_bytes += oss_downsample(data, length, | |
320 effect.frequency, output.frequency); | |
321 } | |
322 | |
323 static void | |
324 swap_endian(guint16 * data, int length) | |
325 { | |
326 int i; | |
327 for (i = 0; i < length; i += 2, data++) | |
328 *data = GUINT16_SWAP_LE_BE(*data); | |
329 } | |
330 | |
331 #define NOT_NATIVE_ENDIAN ((IS_BIG_ENDIAN && \ | |
332 (output.format.oss == AFMT_S16_LE || \ | |
333 output.format.oss == AFMT_U16_LE)) || \ | |
334 (!IS_BIG_ENDIAN && \ | |
335 (output.format.oss == AFMT_S16_BE || \ | |
336 output.format.oss == AFMT_U16_BE))) | |
337 | |
338 | |
339 #define RESAMPLE_STEREO(sample_type) \ | |
340 do { \ | |
341 const gint shift = sizeof (sample_type); \ | |
342 gint i, in_samples, out_samples, x, delta; \ | |
343 sample_type *inptr = (sample_type *)ob, *outptr; \ | |
344 guint nlen = (((length >> shift) * espeed) / speed); \ | |
345 if (nlen == 0) \ | |
346 break; \ | |
347 nlen <<= shift; \ | |
348 if (NOT_NATIVE_ENDIAN) \ | |
349 swap_endian(ob, length); \ | |
350 if(nlen > nbuffer_size) \ | |
351 { \ | |
352 nbuffer = g_realloc(nbuffer, nlen); \ | |
353 nbuffer_size = nlen; \ | |
354 } \ | |
355 outptr = (sample_type *)nbuffer; \ | |
356 in_samples = length >> shift; \ | |
357 out_samples = nlen >> shift; \ | |
358 delta = (in_samples << 12) / out_samples; \ | |
359 for (x = 0, i = 0; i < out_samples; i++) \ | |
360 { \ | |
361 gint x1, frac; \ | |
362 x1 = (x >> 12) << 12; \ | |
363 frac = x - x1; \ | |
364 *outptr++ = \ | |
365 (sample_type) \ | |
366 ((inptr[(x1 >> 12) << 1] * \ | |
367 ((1<<12) - frac) + \ | |
368 inptr[((x1 >> 12) + 1) << 1] * \ | |
369 frac) >> 12); \ | |
370 *outptr++ = \ | |
371 (sample_type) \ | |
372 ((inptr[((x1 >> 12) << 1) + 1] * \ | |
373 ((1<<12) - frac) + \ | |
374 inptr[(((x1 >> 12) + 1) << 1) + 1] * \ | |
375 frac) >> 12); \ | |
376 x += delta; \ | |
377 } \ | |
378 if (NOT_NATIVE_ENDIAN) \ | |
379 swap_endian(nbuffer, nlen); \ | |
380 w = write_all(fd, nbuffer, nlen); \ | |
381 } while (0) | |
382 | |
383 | |
384 #define RESAMPLE_MONO(sample_type) \ | |
385 do { \ | |
386 const gint shift = sizeof (sample_type) - 1; \ | |
387 gint i, x, delta, in_samples, out_samples; \ | |
388 sample_type *inptr = (sample_type *)ob, *outptr; \ | |
389 guint nlen = (((length >> shift) * espeed) / speed); \ | |
390 if (nlen == 0) \ | |
391 break; \ | |
392 nlen <<= shift; \ | |
393 if (NOT_NATIVE_ENDIAN) \ | |
394 swap_endian(ob, length); \ | |
395 if(nlen > nbuffer_size) \ | |
396 { \ | |
397 nbuffer = g_realloc(nbuffer, nlen); \ | |
398 nbuffer_size = nlen; \ | |
399 } \ | |
400 outptr = (sample_type *)nbuffer; \ | |
401 in_samples = length >> shift; \ | |
402 out_samples = nlen >> shift; \ | |
403 delta = ((length >> shift) << 12) / out_samples; \ | |
404 for (x = 0, i = 0; i < out_samples; i++) \ | |
405 { \ | |
406 gint x1, frac; \ | |
407 x1 = (x >> 12) << 12; \ | |
408 frac = x - x1; \ | |
409 *outptr++ = \ | |
410 (sample_type) \ | |
411 ((inptr[x1 >> 12] * ((1<<12) - frac) + \ | |
412 inptr[(x1 >> 12) + 1] * frac) >> 12); \ | |
413 x += delta; \ | |
414 } \ | |
415 if (NOT_NATIVE_ENDIAN) \ | |
416 swap_endian(nbuffer, nlen); \ | |
417 w = write_all(fd, nbuffer, nlen); \ | |
418 } while (0) | |
419 | |
420 | |
421 static gint | |
422 oss_downsample(gpointer ob, guint length, guint speed, guint espeed) | |
423 { | |
424 guint w = 0; | |
425 static gpointer nbuffer = NULL; | |
701
d539e5c5f730
[svn] Fixes of the remaining GCC 4.1 warnings from external contributor Diego "Flameeyes" Petteno (Gentoo).
chainsaw
parents:
517
diff
changeset
|
426 static guint nbuffer_size = 0; |
61 | 427 |
428 switch (output.format.oss) { | |
429 case AFMT_S16_BE: | |
430 case AFMT_S16_LE: | |
431 if (output.channels == 2) | |
432 RESAMPLE_STEREO(gint16); | |
433 else | |
434 RESAMPLE_MONO(gint16); | |
435 break; | |
436 case AFMT_U16_BE: | |
437 case AFMT_U16_LE: | |
438 if (output.channels == 2) | |
439 RESAMPLE_STEREO(guint16); | |
440 else | |
441 RESAMPLE_MONO(guint16); | |
442 break; | |
443 case AFMT_S8: | |
444 if (output.channels == 2) | |
445 RESAMPLE_STEREO(gint8); | |
446 else | |
447 RESAMPLE_MONO(gint8); | |
448 break; | |
449 case AFMT_U8: | |
450 if (output.channels == 2) | |
451 RESAMPLE_STEREO(guint8); | |
452 else | |
453 RESAMPLE_MONO(guint8); | |
454 break; | |
455 } | |
456 return w; | |
457 } | |
458 | |
459 void | |
460 oss_write(gpointer ptr, int length) | |
461 { | |
462 int cnt, off = 0; | |
463 | |
464 if (!realtime) { | |
465 remove_prebuffer = FALSE; | |
466 | |
467 written += length; | |
468 while (length > 0) { | |
469 cnt = MIN(length, buffer_size - wr_index); | |
470 memcpy(buffer + wr_index, (char *) ptr + off, cnt); | |
471 wr_index = (wr_index + cnt) % buffer_size; | |
472 length -= cnt; | |
473 off += cnt; | |
474 } | |
475 } | |
476 else { | |
477 if (paused) | |
478 return; | |
479 oss_write_audio(ptr, length); | |
480 written += length; | |
481 } | |
482 } | |
483 | |
484 void | |
485 oss_close(void) | |
486 { | |
487 if (!going) | |
488 return; | |
489 going = 0; | |
490 if (!realtime) | |
491 g_thread_join(buffer_thread); | |
492 else { | |
493 ioctl(fd, SNDCTL_DSP_RESET, 0); | |
494 close(fd); | |
495 } | |
496 g_free(device_name); | |
497 oss_free_convert_buffer(); | |
498 wr_index = 0; | |
499 rd_index = 0; | |
500 } | |
501 | |
502 void | |
503 oss_flush(gint time) | |
504 { | |
505 if (!realtime) { | |
506 flush = time; | |
507 while (flush != -1) | |
508 xmms_usleep(10000); | |
509 } | |
510 else { | |
511 ioctl(fd, SNDCTL_DSP_RESET, 0); | |
512 close(fd); | |
513 fd = open(device_name, O_WRONLY); | |
514 oss_set_audio_params(); | |
515 output_time_offset = time; | |
516 written = ((guint64) time * input.bps) / 1000; | |
517 output_bytes = 0; | |
518 } | |
519 } | |
520 | |
521 void | |
522 oss_pause(short p) | |
523 { | |
524 if (!realtime) { | |
525 if (p == TRUE) | |
526 do_pause = TRUE; | |
527 else | |
528 unpause = TRUE; | |
529 } | |
530 else | |
531 paused = p; | |
532 | |
533 } | |
534 | |
535 gpointer | |
536 oss_loop(gpointer arg) | |
537 { | |
538 gint length, cnt; | |
539 fd_set set; | |
540 struct timeval tv; | |
541 | |
542 while (going) { | |
543 if (oss_used() > prebuffer_size) | |
544 prebuffer = FALSE; | |
545 if (oss_used() > 0 && !paused && !prebuffer) { | |
546 tv.tv_sec = 0; | |
547 tv.tv_usec = 10000; | |
548 FD_ZERO(&set); | |
549 FD_SET(fd, &set); | |
550 if (!select_works || (select(fd + 1, NULL, &set, NULL, &tv) > 0)) { | |
551 length = MIN(blk_size, oss_used()); | |
552 while (length > 0) { | |
553 cnt = MIN(length, buffer_size - rd_index); | |
554 oss_write_audio(buffer + rd_index, cnt); | |
555 rd_index = (rd_index + cnt) % buffer_size; | |
556 length -= cnt; | |
557 } | |
558 if (!oss_used()) | |
559 ioctl(fd, SNDCTL_DSP_POST, 0); | |
560 } | |
561 } | |
562 else | |
563 xmms_usleep(10000); | |
564 oss_calc_device_buffer_used(); | |
565 if (do_pause && !paused) { | |
566 do_pause = FALSE; | |
567 paused = TRUE; | |
568 /* | |
569 * We lose some data here that is sent to the | |
570 * soundcard, but not yet played. I don't | |
571 * think this is worth fixing. | |
572 */ | |
573 ioctl(fd, SNDCTL_DSP_RESET, 0); | |
574 } | |
575 else if (unpause && paused) { | |
576 unpause = FALSE; | |
577 close(fd); | |
578 fd = open(device_name, O_WRONLY); | |
579 oss_set_audio_params(); | |
580 paused = FALSE; | |
581 } | |
582 | |
583 if (flush != -1) { | |
584 /* | |
585 * This close and open is a work around of a | |
586 * bug that exists in some drivers which cause | |
587 * the driver to get fucked up by a reset | |
588 */ | |
589 | |
590 ioctl(fd, SNDCTL_DSP_RESET, 0); | |
591 close(fd); | |
592 fd = open(device_name, O_WRONLY); | |
593 oss_set_audio_params(); | |
594 output_time_offset = flush; | |
595 written = ((guint64) flush * input.bps) / 1000; | |
596 rd_index = wr_index = output_bytes = 0; | |
597 flush = -1; | |
598 prebuffer = TRUE; | |
599 } | |
600 | |
601 } | |
602 | |
603 ioctl(fd, SNDCTL_DSP_RESET, 0); | |
604 close(fd); | |
605 g_free(buffer); | |
606 return NULL; | |
607 } | |
608 | |
609 void | |
610 oss_set_audio_params(void) | |
611 { | |
612 int frag, stereo, ret; | |
613 struct timeval tv; | |
614 fd_set set; | |
615 | |
616 ioctl(fd, SNDCTL_DSP_RESET, 0); | |
617 frag = (NFRAGS << 16) | fragsize; | |
618 ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag); | |
619 /* | |
620 * Set the stream format. This ioctl() might fail, but should | |
621 * return a format that works if it does. | |
622 */ | |
623 ioctl(fd, SNDCTL_DSP_SETFMT, &output.format.oss); | |
624 if (ioctl(fd, SNDCTL_DSP_SETFMT, &output.format.oss) == -1) | |
625 g_warning("SNDCTL_DSP_SETFMT ioctl failed: %s", strerror(errno)); | |
626 | |
627 stereo = output.channels - 1; | |
628 ioctl(fd, SNDCTL_DSP_STEREO, &stereo); | |
629 output.channels = stereo + 1; | |
630 | |
631 oss_stereo_convert_func = oss_get_stereo_convert_func(output.channels, | |
632 effect.channels); | |
633 | |
634 if (ioctl(fd, SNDCTL_DSP_SPEED, &output.frequency) == -1) | |
635 g_warning("SNDCTL_DSP_SPEED ioctl failed: %s", strerror(errno)); | |
636 | |
637 if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &blk_size) == -1) | |
638 blk_size = 1L << fragsize; | |
639 | |
640 oss_convert_func = | |
641 oss_get_convert_func(output.format.oss, | |
642 oss_get_format(effect.format.xmms)); | |
643 | |
644 /* | |
645 * Stupid hack to find out if the driver support selects, some | |
646 * drivers won't work properly without a select and some won't | |
647 * work with a select :/ | |
648 */ | |
649 | |
650 tv.tv_sec = 0; | |
651 tv.tv_usec = 50000; | |
652 FD_ZERO(&set); | |
653 FD_SET(fd, &set); | |
654 ret = select(fd + 1, NULL, &set, NULL, &tv); | |
655 if (ret > 0) | |
656 select_works = TRUE; | |
657 else | |
658 select_works = FALSE; | |
659 } | |
660 | |
661 gint | |
662 oss_open(AFormat fmt, gint rate, gint nch) | |
663 { | |
664 | |
665 if (oss_cfg.use_alt_audio_device && oss_cfg.alt_audio_device) | |
666 device_name = g_strdup(oss_cfg.alt_audio_device); | |
667 else { | |
668 if (oss_cfg.audio_device > 0) | |
669 device_name = | |
670 g_strdup_printf("%s%d", DEV_DSP, oss_cfg.audio_device); | |
671 else | |
672 device_name = g_strdup(DEV_DSP); | |
673 } | |
674 | |
675 fd = open(device_name, O_WRONLY); | |
676 | |
677 if (fd == -1) { | |
678 g_warning("oss_open(): Failed to open audio device (%s): %s", | |
679 device_name, strerror(errno)); | |
680 g_free(device_name); | |
681 return 0; | |
682 } | |
683 | |
684 input.format.xmms = fmt; | |
685 input.frequency = rate; | |
686 input.channels = nch; | |
687 input.bps = oss_calc_bitrate(oss_get_format(fmt), rate, nch); | |
688 | |
689 oss_setup_format(fmt, rate, nch); | |
690 | |
691 realtime = xmms_check_realtime_priority(); | |
692 | |
693 if (!realtime) { | |
694 buffer_size = (oss_cfg.buffer_size * input.bps) / 1000; | |
695 if (buffer_size < 8192) | |
696 buffer_size = 8192; | |
697 prebuffer_size = (buffer_size * oss_cfg.prebuffer) / 100; | |
698 if (buffer_size - prebuffer_size < 4096) | |
699 prebuffer_size = buffer_size - 4096; | |
700 | |
701 buffer_size += device_buffer_size; | |
702 buffer = g_malloc0(buffer_size); | |
703 } | |
704 flush = -1; | |
705 prebuffer = TRUE; | |
706 wr_index = rd_index = output_time_offset = written = output_bytes = 0; | |
707 paused = FALSE; | |
708 do_pause = FALSE; | |
709 unpause = FALSE; | |
710 remove_prebuffer = FALSE; | |
711 | |
712 going = 1; | |
713 if (!realtime) | |
714 buffer_thread = g_thread_create(oss_loop, NULL, TRUE, NULL); | |
715 return 1; | |
716 } | |
517
55dc40ff1aff
[svn] Add tell_audio(AFormat *, gint *, gint *), for retrieving audio
nenolod
parents:
382
diff
changeset
|
717 |
55dc40ff1aff
[svn] Add tell_audio(AFormat *, gint *, gint *), for retrieving audio
nenolod
parents:
382
diff
changeset
|
718 void oss_tell(AFormat * fmt, gint * rate, gint * nch) |
55dc40ff1aff
[svn] Add tell_audio(AFormat *, gint *, gint *), for retrieving audio
nenolod
parents:
382
diff
changeset
|
719 { |
55dc40ff1aff
[svn] Add tell_audio(AFormat *, gint *, gint *), for retrieving audio
nenolod
parents:
382
diff
changeset
|
720 (*fmt) = input.format.xmms; |
55dc40ff1aff
[svn] Add tell_audio(AFormat *, gint *, gint *), for retrieving audio
nenolod
parents:
382
diff
changeset
|
721 (*rate) = input.frequency; |
55dc40ff1aff
[svn] Add tell_audio(AFormat *, gint *, gint *), for retrieving audio
nenolod
parents:
382
diff
changeset
|
722 (*nch) = input.channels; |
55dc40ff1aff
[svn] Add tell_audio(AFormat *, gint *, gint *), for retrieving audio
nenolod
parents:
382
diff
changeset
|
723 } |