pkgsrc/audio/rplay/patches/patch-cb
ben b3ed91c94a Add support for NetBSD's native audio API, from Ole Hellqvist.
This removes some limitations and addresses PR#28352
2004-12-22 16:18:42 +00:00

602 lines
13 KiB
Text

$NetBSD: patch-cb,v 1.1 2004/12/22 16:19:34 ben Exp $
--- rplayd/audio/audio_NetBSD.c.orig Sat Dec 18 17:40:37 2004
+++ rplayd/audio/audio_NetBSD.c Sat Dec 18 18:19:18 2004
@@ -0,0 +1,598 @@
+/* #Id: audio_NetBSD 0.02 2004/12/18 OHt # */
+
+/*
+ *
+ * This file is part of rplay.
+ *
+ * rplay is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * rplay is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with rplay; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+
+#include "rplayd.h"
+
+/*
+ * System audio include files:
+ */
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/fcntl.h>
+#include <sys/errno.h>
+#include <sys/audioio.h>
+#include <errno.h>
+
+/*
+ * External variables:
+ */
+extern char *rplay_audio_device;
+extern int rplay_audio_sample_rate;
+extern int rplay_audio_channels;
+extern int rplay_audio_precision;
+extern int rplay_audio_format;
+extern int rplay_audio_port;
+extern int optional_sample_rate;
+extern int optional_precision;
+extern int optional_channels;
+extern int optional_format;
+extern int optional_port;
+
+/*
+ * Internal variables:
+ */
+static int rplay_audio_fd = -1;
+static RPLAY_AUDIO_TABLE generic_table[] =
+{
+ {44100, RPLAY_FORMAT_LINEAR_16, 16, 2},
+ {0, 0, 0, 0}
+};
+
+static RPLAY_AUDIO_TABLE NetBSD_table[50 * AUDIO_ENCODING_MPEG_L2_SYSTEM];
+ int enc_table[20];
+ int i;
+
+
+ const int sratetab[]=
+ { 6615,
+ 8000,
+ 9600,
+ 11025,
+ 16000,
+ 22050,
+ 32000,
+ 44100,
+ 48000
+ };
+
+
+char *encoding_name;
+audio_encoding_t enc_st;
+audio_info_t prinfo;
+int n =1;
+
+
+char *soundbuff;
+audio_info_t a;
+
+/*
+ * Initialize the audio device.
+ * This routine must set the following external variables:
+ * rplay_audio_sample_rate
+ * rplay_audio_precision
+ * rplay_audio_channels
+ * rplay_audio_format
+ * rplay_audio_port
+ *
+ * and may use the following optional parameters:
+ * optional_sample_rate
+ * optional_precision
+ * optional_channels
+ * optional_format
+ * optional_port
+ *
+ * optional_* variables with values of zero should be ignored.
+ *
+ * Return 0 on success and -1 on error.
+ */
+int
+rplay_audio_init()
+{
+
+ audio_info_t a;
+ audio_device_t d;
+ int enc_table[20];
+ int i;
+ int j;
+
+ report(REPORT_DEBUG,"rplay_audio_init()- rplay_audio_fd : %d \n", rplay_audio_fd );
+
+ if (rplay_audio_fd == -1)
+ {
+ rplay_audio_open();
+ if (rplay_audio_fd == -1)
+ {
+ report(REPORT_ERROR, "rplay_audio_init: cannot open %s\n",
+ rplay_audio_device);
+ return -1;
+ }
+ }
+
+ if (ioctl(rplay_audio_fd, AUDIO_GETINFO, &a) < 0)
+ {
+ report(REPORT_ERROR, "rplay_audio_init: failed to get audio info%s\n",
+ rplay_audio_device);
+ return -1;
+ }
+
+
+ if (ioctl(rplay_audio_fd, AUDIO_GETDEV, &d) < 0)
+ {
+ report(REPORT_ERROR, "rplay_audio_init: AUDIO_GETDEV: %s\n",
+ sys_err_str(errno));
+ return -1;
+ }
+ for (i = AUDIO_ENCODING_NONE ; i < AUDIO_ENCODING_MPEG_L2_SYSTEM; ++i)
+ {
+ enc_st.index = i;
+ if (ioctl(rplay_audio_fd, AUDIO_GETENC, &enc_st) == -1)
+ {
+ asprintf(&encoding_name, "%d", prinfo.play.encoding);
+ }
+ else
+ {
+ switch (enc_st.encoding)
+ {
+ case AUDIO_ENCODING_ULAW:
+ enc_table[i] = RPLAY_FORMAT_ULAW;
+ break;
+ case AUDIO_ENCODING_SLINEAR:
+ enc_table[i]= RPLAY_FORMAT_LINEAR_8;
+ break;
+ case AUDIO_ENCODING_ULINEAR:
+ enc_table[i] = RPLAY_FORMAT_ULINEAR_8;
+ break;
+ case AUDIO_ENCODING_SLINEAR_LE:
+ enc_table[i] =RPLAY_FORMAT_LINEAR_16;
+ break;
+ case AUDIO_ENCODING_ULINEAR_LE:
+ enc_table[i]= RPLAY_FORMAT_ULINEAR_16;
+ break;
+ default:
+ enc_table[i] = RPLAY_FORMAT_NONE;
+ break;
+
+ }
+ }
+ }
+ for (j = 1 ; j < 7 ; j++)
+ {
+ prinfo.play.sample_rate = sratetab[j];
+
+ for (i = AUDIO_ENCODING_NONE ; i <= AUDIO_ENCODING_MPEG_L2_SYSTEM; i++)
+ {
+ if (enc_table[i] != RPLAY_FORMAT_NONE)
+ {
+
+ int k;
+ enc_st.index = i;
+ prinfo.play.encoding = i;
+ AUDIO_INITINFO (&prinfo) ;
+ /* for (j = 1 ; j < 7 ; j++)
+ {
+ int k;
+ prinfo.play.sample_rate = sratetab[j];*/
+ for (k = 1 ; k < 5 ; k++)
+ {
+ switch (k)
+ {
+ case 1:
+ prinfo.play.precision = 8;
+ prinfo.play.channels = 1;
+ break;
+ case 2:
+ prinfo.play.precision = 16;
+ prinfo.play.channels = 1;
+ break;
+ case 3:
+ prinfo.play.precision = 8;
+ prinfo.play.channels = 2;
+ break;
+ case 4:
+ prinfo.play.precision = 16;
+ prinfo.play.channels = 2;
+ break;
+ }
+ if (ioctl(rplay_audio_fd, AUDIO_SETINFO, &prinfo) != -1)
+ {
+ NetBSD_table[n].format = enc_table[i];
+ NetBSD_table[n].sample_rate = prinfo.play.sample_rate;
+ NetBSD_table[n].bits = prinfo.play.precision;
+ NetBSD_table[n].channels = prinfo.play.channels;
+ n++;
+ }
+ }
+ }
+ }
+ }
+ report(REPORT_DEBUG," rplay_audio_bufsize: %d \n", rplay_audio_bufsize);
+ report(REPORT_DEBUG," rplay_audio_rate: %d \n", rplay_audio_rate);
+
+ {
+ NetBSD_table[n].format = RPLAY_FORMAT_NONE ;
+ NetBSD_table[n].sample_rate = 0;
+ NetBSD_table[n].bits = 0;
+ NetBSD_table[n].channels = 0 ;
+ }
+
+ n = 1;
+
+ rplay_audio_sample_rate = optional_sample_rate ? optional_sample_rate : 44100;
+ rplay_audio_precision = optional_precision ? optional_precision : 16;
+ rplay_audio_channels = optional_channels ? optional_channels : 2;
+ rplay_audio_format = optional_format ? optional_format :
+ rplay_audio_precision == 16 ? RPLAY_FORMAT_LINEAR_16 : RPLAY_FORMAT_LINEAR_8;
+ rplay_audio_table =( RPLAY_AUDIO_TABLE *) NetBSD_table ;
+ report(REPORT_DEBUG, "%s device detected\n", d.name);
+
+
+
+ /* Verify the precision and format. */
+ switch (rplay_audio_precision)
+ {
+ case 8:
+ if (rplay_audio_format != RPLAY_FORMAT_ULAW
+ && rplay_audio_format != RPLAY_FORMAT_LINEAR_8 && rplay_audio_format != RPLAY_FORMAT_ULINEAR_8)
+ {
+ report(REPORT_ERROR, "rplay_audio_init: can't use %d bits with format=%d\n",
+ rplay_audio_precision, rplay_audio_format);
+ return -1;
+ }
+ break;
+
+ case 16:
+ if (rplay_audio_format != RPLAY_FORMAT_LINEAR_16)
+ {
+ report(REPORT_ERROR, "rplay_audio_init: can't use %d bits with format=%d\n",
+ rplay_audio_precision, rplay_audio_format);
+ return -1;
+ }
+ break;
+
+ default:
+ report(REPORT_ERROR, "rplay_audio_init: `%d' unsupported audio precision\n",
+ rplay_audio_precision);
+ return -1;
+ }
+
+ AUDIO_INITINFO(&a);
+
+ switch (rplay_audio_format)
+ {
+ case RPLAY_FORMAT_ULAW:
+ a.play.encoding = AUDIO_ENCODING_ULAW;
+ break;
+
+ case RPLAY_FORMAT_LINEAR_8:
+ a.play.encoding = AUDIO_ENCODING_SLINEAR;
+ break;
+ case RPLAY_FORMAT_LINEAR_16:
+ a.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
+ break;
+
+ default:
+ report(REPORT_ERROR, "rplay_audio_init: unsupported audio format `%d'\n",
+ rplay_audio_format);
+ return -1;
+ }
+
+
+ a.play.sample_rate = rplay_audio_sample_rate;
+ a.play.precision = rplay_audio_precision;
+ a.play.channels = rplay_audio_channels;
+
+ if (ioctl(rplay_audio_fd, AUDIO_SETINFO, &a) < 0)
+ {
+ report(REPORT_DEBUG, "rplay_audio_init: AUDIO_SETINFO: %s\n", sys_err_str(errno));
+ report(REPORT_ERROR, "rplay_audio_init: AUDIO_SETINFO: %s\n", sys_err_str(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+/***************************************************************/
+/*
+ * Open the audio device.
+ *
+ * Return 0 on success and -1 on error.
+ */
+
+
+int
+rplay_audio_open()
+{
+ int flags;
+
+ rplay_audio_fd = open(rplay_audio_device, O_WRONLY | O_NDELAY, 0);
+ report(REPORT_DEBUG,"rplay_audio_open()- rplay_audio_fd : %d \n", rplay_audio_fd );
+
+
+ if (rplay_audio_fd < 0)
+ {
+ report(REPORT_ERROR,"rplay_audio_open: rplay_audio_fd %d < 0, \n", rplay_audio_fd );
+ return -1;
+ }
+
+ if (fcntl(rplay_audio_fd, F_SETFD, 1) < 0)
+ {
+ report(REPORT_ERROR,
+ "rplay_audio_open: close-on-exec %d\n",
+ sys_err_str(errno));
+ /* return -1; */
+ }
+
+ if (rplay_audio_init() < 0)
+ {
+ return -1;
+ }
+
+ /*
+ * Make sure the audio device writes are non-blocking.
+ */
+ flags = fcntl(rplay_audio_fd, F_GETFL, 0);
+ if (flags < 0)
+ {
+ return -1;
+ }
+ flags |= FNDELAY;
+ if (fcntl(rplay_audio_fd, F_SETFL, flags) < 0)
+ {
+ return -1;
+ }
+ soundbuff = malloc( a.play.buffer_size);
+ return 0;
+}
+
+/*
+ * Is the audio device open?
+ *
+ * Return 1 for true and 0 for false.
+ */
+int
+rplay_audio_isopen()
+{
+ if (rplay_audio_fd > 0)
+ {
+ return 1;
+ }
+ else
+ {
+ report(REPORT_DEBUG,"rplay_audio_isopen()- rplay_audio_fd : %d \n", rplay_audio_fd );
+ return 0;
+ }
+ /*return rplay_audio_fd != -1;*/
+}
+
+/*
+ * Flush the audio device.
+ *
+ * Return 0 on success and -1 on error.
+ */
+int
+rplay_audio_flush()
+{
+ audio_info_t info;
+ report(REPORT_DEBUG,"rplay_audio_flush()- rplay_audio_fd : %d \n", rplay_audio_fd );
+
+ if (rplay_audio_fd != -1)
+ {
+ ioctl(rplay_audio_fd, AUDIO_GETINFO, &info);
+ /* ioctl(rplay_audio_fd, AUDIO_DRAIN, 0);*/
+ ioctl(rplay_audio_fd , AUDIO_FLUSH, NULL);
+ if ((ioctl(rplay_audio_fd, AUDIO_DRAIN)) < 0)
+ {
+ report(REPORT_DEBUG,"audio drain ioctl failed- rplay_audio_fd : %d \n",rplay_audio_fd ) ;
+ return -1;
+ }
+ }
+ ioctl(rplay_audio_fd , AUDIO_SETINFO, &info);
+ return 0;
+}
+
+
+/************************************************************************/
+/*
+ * Write nbytes from buf to the audio device.
+ *
+ * Return the number of bytes written on success and -1 on error.
+ */
+
+#ifdef __STDC__
+int
+rplay_audio_write(char *buf, int nbytes)
+#else
+int
+rplay_audio_write(buf, nbytes)
+ char *buf;
+ int nbytes;
+#endif
+{
+ int n, nleft, nwritten;
+ char *p;
+ audio_info_t a;
+
+ nleft = nbytes;
+ nwritten = 0;
+
+
+ if (ioctl(rplay_audio_fd, AUDIO_GETINFO, &a) < 0)
+ {
+ report(REPORT_ERROR, "rplay_audio_init: failed to get audio info%s\n",
+ rplay_audio_device);
+ return -1;
+ }
+
+
+ for (p = buf; nleft > 0; nleft -= n, p += n)
+ {
+ n = write(rplay_audio_fd, p, nleft);
+ if (n < 0)
+ {
+ if (errno == EWOULDBLOCK)
+ {
+ return nwritten;
+ }
+ else if (errno != EINTR)
+ {
+ return -1;
+ }
+ n = 0;
+ }
+ else
+ {
+ nwritten += n;
+ }
+ }
+
+
+
+
+
+ return nwritten;
+}
+
+/*
+ * Close the audio device.
+ *
+ * Return 0 on success and -1 on error.
+ */
+int
+rplay_audio_close()
+{
+ report(REPORT_DEBUG," 1 rplay_audio_close()- rplay_audio_fd : %d \n", rplay_audio_fd );
+
+ if (rplay_audio_fd != -1)
+ {
+ if (close(rplay_audio_fd) == 0)
+ {
+ rplay_audio_fd = -1;
+ return 0;
+ }
+ else
+ {
+ report(REPORT_DEBUG," 2 rplay_audio_close()- rplay_audio_fd : %d \n", rplay_audio_fd );
+ return -1;
+ }
+ }
+
+
+
+ /* return 0;*/
+}
+
+/*
+ * Return the volume of the audio device.
+ *
+ * Return 0-255 or -1 on error.
+ */
+int
+rplay_audio_get_volume()
+{
+#ifdef FAKE_VOLUME
+ report(REPORT_DEBUG,"rplay_audio_get_volume() fake - rplay_audio_volume : %d \n",rplay_audio_volume );
+
+ return rplay_audio_volume;
+#else /* not FAKE_VOLUME */
+ audio_info_t a;
+
+ if (rplay_audio_fd < 0)
+ {
+ rplay_audio_open();
+ }
+ if (rplay_audio_fd < 0)
+ {
+ return -1;
+ }
+ if (ioctl(rplay_audio_fd, AUDIO_GETINFO, &a) < 0)
+ {
+ return -1;
+ }
+ else
+ {
+ report(REPORT_DEBUG,"rplay_audio_get_volume()- a.play.gain : %d \n",a.play.gain );
+
+ return a.play.gain;
+ }
+#endif /* not FAKE_VOLUME */
+}
+
+/*
+ * Set the volume of the audio device.
+ * Input should be 0-255.
+ *
+ * Return the volume of the audio device 0-255 or -1.
+ */
+#ifdef __STDC__
+int
+rplay_audio_set_volume(int volume)
+#else
+int
+rplay_audio_set_volume(volume)
+ int volume;
+#endif
+{
+#ifdef FAKE_VOLUME
+ if (volume < RPLAY_MIN_VOLUME)
+ {
+ volume = RPLAY_MIN_VOLUME;
+ }
+ else if (volume > RPLAY_MAX_VOLUME)
+ {
+ volume = RPLAY_MAX_VOLUME;
+ }
+ rplay_audio_volume = volume;
+ report(REPORT_DEBUG,"rplay_audio_set_volume()- rplay_audio_volume : %d \n", rplay_audio_volume );
+
+
+ return rplay_audio_volume;
+#else /* not FAKE_VOLUME */
+ audio_info_t a;
+
+ rplay_audio_volume = 0;
+
+ if (rplay_audio_fd < 0)
+ {
+ rplay_audio_open();
+ }
+ if (rplay_audio_fd < 0)
+ {
+ return -1;
+ }
+
+ AUDIO_INITINFO(&a);
+ a.play.gain = volume;
+ report(REPORT_DEBUG,"rplay_audio_set_volume()- a.play.gain : %d \n",a.play.gain );
+
+ if (ioctl(rplay_audio_fd, AUDIO_SETINFO, &a) < 0)
+ {
+ return -1;
+ }
+
+ rplay_audio_volume = rplay_audio_get_volume();
+
+ return rplay_audio_volume;
+#endif /* not FAKE_VOLUME */
+}