$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 +#include +#include +#include +#include +#include +#include + +/* + * 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 */ +}