b3ed91c94a
This removes some limitations and addresses PR#28352
602 lines
13 KiB
Text
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 */
|
|
+}
|