1 /* XMMS - Cross-platform multimedia player
2 * Copyright (C) 1998-1999 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include <sys/types.h>
30 #include <sys/ioctl.h>
32 #include <sys/soundcard.h>
33 //#include <machine/soundcard.h>
36 void oss_set_audio_params(void);
39 /* All that remains of glib usage... */
43 typedef unsigned char guchar;
44 typedef unsigned short gushort;
45 typedef unsigned int guint;
46 typedef unsigned long gulong;
48 #define min(x,y) ((x)<(y)?(x):(y))
52 static gboolean going = FALSE, prebuffer = FALSE, remove_prebuffer = FALSE;
53 static gboolean paused = FALSE, unpause = FALSE, do_pause = FALSE;
54 static int buffer_size, prebuffer_size, blk_size;
55 static int rd_index = 0, wr_index = 0;
56 static int output_time_offset = 0, written = 0, output_bytes = 0;
59 static int fragsize, format, channels;
60 static int frequency, efrequency, device_buffer_size;
61 static char device_name[ 16 ];
62 static pthread_t buffer_thread;
63 static gboolean realtime = FALSE;
71 printf( "XMMS OSS Driver 0.9\n" );
75 int oss_get_written_time(void)
79 return (int) (((float) written * 1000) / (float) (bps));
82 int oss_get_output_time(void)
84 audio_buf_info buf_info;
92 if (!ioctl(fd, SNDCTL_DSP_GETOSPACE, &buf_info))
93 bytes = output_bytes - ((buf_info.fragstotal - buf_info.fragments) * buf_info.fragsize);
102 return output_time_offset + (int) ((float) ((bytes) * 1000.0) / (float) ebps);
111 if (wr_index >= rd_index)
112 return wr_index - rd_index;
113 return buffer_size - (rd_index - wr_index);
117 int oss_playing(void)
119 audio_buf_info buf_info;
122 if (!ioctl(fd, SNDCTL_DSP_GETOSPACE, &buf_info))
123 bytes = ((buf_info.fragstotal - buf_info.fragments - 3) * buf_info.fragsize);
127 if (!oss_used() && bytes <= 0)
137 if (remove_prebuffer && prebuffer)
140 remove_prebuffer = FALSE;
143 remove_prebuffer = TRUE;
145 if (rd_index > wr_index)
146 return (rd_index - wr_index) - device_buffer_size - 1;
147 return (buffer_size - (wr_index - rd_index)) - device_buffer_size - 1;
156 int oss_downsample(guchar * ob, guint length, guint speed, guint espeed)
158 guint nlen, i, off, d, w;
160 if ((format == AFMT_U16_BE || format == AFMT_U16_LE || format == AFMT_S16_BE || format == AFMT_S16_LE) && channels == 2)
162 gulong *nbuffer, *obuffer, *ptr;
164 obuffer = (gulong *) ob;
167 nlen = (length * espeed) / speed;
168 d = (speed << 8) / espeed;
170 nbuffer = malloc(nlen << 2);
171 for (i = 0, off = 0, ptr = nbuffer; i < nlen; i++)
173 *ptr++ = obuffer[off >> 8];
176 w = write(fd, nbuffer, nlen << 2);
179 else if (((format == AFMT_U16_BE || format == AFMT_U16_LE || format == AFMT_S16_BE || format == AFMT_S16_LE) && channels == 1)
180 || ((format == AFMT_U8 || format == AFMT_S8) && channels == 2))
182 gushort *nbuffer, *obuffer, *ptr;
184 obuffer = (gushort *) ob;
187 nlen = (length * espeed) / speed;
188 d = (speed << 8) / espeed;
190 nbuffer = malloc(nlen << 1);
191 for (i = 0, off = 0, ptr = nbuffer; i < nlen; i++)
193 *ptr++ = obuffer[off >> 8];
196 w = write(fd, nbuffer, nlen << 1);
201 guchar *nbuffer, *obuffer, *ptr;
205 nlen = (length * espeed) / speed;
206 d = (speed << 8) / espeed;
208 nbuffer = malloc(nlen);
209 for (i = 0, off = 0, ptr = nbuffer; i < nlen; i++)
211 *ptr++ = obuffer[off >> 8];
214 w = write(fd, nbuffer, nlen);
221 void oss_write(void *ptr, int length)
227 while( oss_free() < length )
230 remove_prebuffer = FALSE;
234 cnt = min(length, buffer_size - wr_index);
235 memcpy(buffer + wr_index, ptr + off, cnt);
236 wr_index = (wr_index + cnt) % buffer_size;
247 if (frequency == efrequency)
248 w = write(fd, ptr, length);
250 w = oss_downsample(ptr, length, frequency, efrequency);
252 if (w == -1 && errno == EIO)
255 fd = open(device_name, O_WRONLY);
256 oss_set_audio_params();
257 if (frequency == efrequency)
258 w = write(fd, ptr, length);
260 w = oss_downsample(ptr, length, frequency, efrequency);
274 pthread_join(buffer_thread, NULL);
277 ioctl(fd, SNDCTL_DSP_RESET, 0);
282 void oss_flush(int time)
292 ioctl(fd, SNDCTL_DSP_RESET, 0);
294 fd = open(device_name, O_WRONLY);
295 oss_set_audio_params();
296 output_time_offset = time;
297 written = (time / 10) * (bps / 100);
302 void oss_pause(short p)
316 void *oss_loop(void *arg)
319 audio_buf_info abuf_info;
323 if (oss_used() > prebuffer_size)
327 if (oss_used() > 0 && !paused && !prebuffer)
329 length = min(blk_size, oss_used());
332 cnt = min(length, buffer_size - rd_index);
334 if (frequency == efrequency)
335 w = write(fd, buffer + rd_index, cnt);
337 w = oss_downsample(buffer + rd_index, cnt, frequency, efrequency);
338 if (w == -1 && errno == EIO)
341 fd = open(device_name, O_WRONLY);
342 oss_set_audio_params();
343 if (frequency == efrequency)
344 w = write(fd, buffer + rd_index, cnt);
346 w = oss_downsample(buffer + rd_index, cnt, frequency, efrequency);
349 rd_index = (rd_index + cnt) % buffer_size;
353 ioctl(fd, SNDCTL_DSP_POST, 0);*/
357 if (do_pause && !paused)
361 if (!ioctl(fd, SNDCTL_DSP_GETOSPACE, &abuf_info))
363 rd_index -= (abuf_info.fragstotal - abuf_info.fragments) * abuf_info.fragsize;
364 output_bytes -= (abuf_info.fragstotal - abuf_info.fragments) * abuf_info.fragsize;
367 rd_index += buffer_size;
368 ioctl(fd, SNDCTL_DSP_RESET, 0);
371 if (unpause && paused)
375 fd = open(device_name, O_WRONLY);
376 oss_set_audio_params();
383 * This close and open is a work around of a bug that exists in some drivers which
384 * cause the driver to get fucked up by a reset
387 ioctl(fd, SNDCTL_DSP_RESET, 0);
389 fd = open(device_name, O_WRONLY);
390 oss_set_audio_params();
391 output_time_offset = flush;
392 written = (flush / 10) * (bps / 100);
393 rd_index = wr_index = output_bytes = 0;
400 ioctl(fd, SNDCTL_DSP_RESET, 0);
402 munlock( buffer, buffer_size );
407 void oss_set_audio_params(void)
411 ioctl(fd, SNDCTL_DSP_RESET, 0);
412 frag = (oss_cfg.fragment_count << 16) | fragsize;
413 ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag);
414 ioctl(fd, SNDCTL_DSP_SETFMT, &format);
415 stereo = channels - 1;
416 ioctl(fd, SNDCTL_DSP_STEREO, &stereo);
417 efrequency = frequency;
418 ioctl(fd, SNDCTL_DSP_SPEED, &efrequency);
419 ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &blk_size);
421 ebps = efrequency * channels;
422 if (format == AFMT_U16_BE || format == AFMT_U16_LE || format == AFMT_S16_BE || format == AFMT_S16_LE)
426 int oss_open(AFormat fmt, int rate, int nch)
437 format = AFMT_U16_LE;
440 format = AFMT_U16_BE;
444 format = AFMT_U16_NE;
446 #ifdef WORDS_BIGENDIAN
447 format = AFMT_U16_BE;
449 format = AFMT_U16_LE;
454 format = AFMT_S16_LE;
457 format = AFMT_S16_BE;
461 format = AFMT_S16_NE;
463 #ifdef WORDS_BIGENDIAN
464 format = AFMT_S16_BE;
466 format = AFMT_S16_LE;
473 if (format == AFMT_U16_BE || format == AFMT_U16_LE || format == AFMT_S16_BE || format == AFMT_S16_LE)
476 while ((1L << fragsize) < bps / 25)
480 device_buffer_size = ((1L << fragsize) * (oss_cfg.fragment_count + 1));
484 buffer_size = (oss_cfg.buffer_size * bps) / 1000;
485 if (buffer_size < 8192)
487 prebuffer_size = (buffer_size * oss_cfg.prebuffer) / 100;
488 if (buffer_size - prebuffer_size < 4096)
489 prebuffer_size = buffer_size - 4096;
491 buffer_size += device_buffer_size;
492 buffer = calloc( 1, buffer_size );
493 mlock(buffer, buffer_size);
498 wr_index = rd_index = output_time_offset = written = output_bytes = 0;
502 remove_prebuffer = FALSE;
504 /*realtime = xmms_check_realtime_priority();*/
505 /*realtime = FALSE;*/
508 if (oss_cfg.audio_device > 0)
509 sprintf( device_name, "/dev/dsp%d", oss_cfg.audio_device );
511 strcpy( device_name, "/dev/dsp" );
513 fd = open(device_name, O_WRONLY);
519 oss_set_audio_params();
521 pthread_create(&buffer_thread, NULL, oss_loop, NULL);
526 static void scan_devices( char* type )
534 printf( "%s\n", type );
536 file = fopen( "/dev/sndstat", "r" );
539 while (fgets(buffer, 255, file))
541 if (found && buffer[0] == '\n')
543 if (buffer[strlen(buffer) - 1] == '\n')
544 buffer[strlen(buffer) - 1] = '\0';
549 tmp2 = strchr(buffer, ':');
559 printf( " %s (default)\n", tmp2 );
563 printf( " %s\n", buffer );
566 if( ! strcasecmp(buffer, type) )
574 void oss_configure(void)
576 printf( "OSS configure not implemented - here are the current devices:\n" );
577 scan_devices( "Audio devices:" );
578 scan_devices( "Mixers:" );
581 oss_cfg.audio_device = audio_device;
582 oss_cfg.mixer_device = mixer_device;
583 oss_cfg.buffer_size = (gint) GTK_ADJUSTMENT(buffer_size_adj)->value;
584 oss_cfg.prebuffer = (gint) GTK_ADJUSTMENT(buffer_pre_adj)->value;
585 oss_cfg.fragment_count = 32;
597 memset(&oss_cfg, 0, sizeof (OSSConfig));
599 oss_cfg.audio_device = 0;
600 oss_cfg.mixer_device = 0;
601 oss_cfg.buffer_size = 3000;
602 oss_cfg.prebuffer = 25;
603 oss_cfg.fragment_count = 3; /*32;*/
606 filename = g_strconcat(g_get_home_dir(), "/.xmms/config", NULL);
607 if (cfgfile = xmms_cfg_open_file(filename))
609 xmms_cfg_read_int(cfgfile, "OSS", "audio_device", &oss_cfg.audio_device);
610 xmms_cfg_read_int(cfgfile, "OSS", "mixer_device", &oss_cfg.mixer_device);
611 xmms_cfg_read_int(cfgfile, "OSS", "buffer_size", &oss_cfg.buffer_size);
612 xmms_cfg_read_int(cfgfile, "OSS", "prebuffer", &oss_cfg.prebuffer);
613 xmms_cfg_free(cfgfile);
619 void oss_get_volume(int *l, int *r)
621 int fd, v, cmd, devs;
624 if (oss_cfg.mixer_device > 0)
625 sprintf( devname, "/dev/mixer%d", oss_cfg.mixer_device );
627 strcpy( devname, "/dev/mixer" );
629 fd = open(devname, O_RDONLY);
632 ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devs);
633 if (devs & SOUND_MASK_PCM)
634 cmd = SOUND_MIXER_READ_PCM;
635 else if (devs & SOUND_MASK_VOLUME)
636 cmd = SOUND_MIXER_READ_VOLUME;
643 *r = (v & 0xFF00) >> 8;
650 void oss_set_volume(int l, int r)
652 int fd, v, cmd, devs;
655 if (oss_cfg.mixer_device > 0)
656 sprintf( devname, "/dev/mixer%d", oss_cfg.mixer_device );
658 strcpy( devname, "/dev/mixer" );
660 fd = open(devname, O_RDONLY);
663 ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devs);
664 if (devs & SOUND_MASK_PCM)
665 cmd = SOUND_MIXER_WRITE_PCM;
666 else if (devs & SOUND_MASK_VOLUME)
667 cmd = SOUND_MIXER_WRITE_VOLUME;
680 OutputPlugin oss_op =
698 oss_get_written_time,
702 OutputPlugin *get_oplugin_info(void)