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