$NetBSD: patch-aa,v 1.5 1998/11/05 02:46:09 mycroft Exp $ --- /dev/null Wed Nov 4 21:26:51 1998 +++ src/auddev_netbsd.c Wed Nov 4 21:27:03 1998 @@ -0,0 +1,423 @@ +/* + * FILE: netbsd.c + * PROGRAM: RAT + * AUTHOR: Isidor Kouvelas + * MODIFIED: Colin Perkins + * + * $Revision: 1.5 $ + * $Date: 1998/11/05 02:46:09 $ + * + * Copyright (c) 1995,1996 University College London + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted, for non-commercial use only, provided + * that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Science + * Department at University College London + * 4. Neither the name of the University nor of the Department may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * Use of this software for commercial purposes is explicitly forbidden + * unless prior written permission is obtained from the authors. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + + +#include "assert.h" +#include "bat_include.h" +#ifdef __NetBSD__ + +static audio_info_t dev_info; +static int mulaw_device = FALSE; /* TRUE if the hardware can only do 8bit mulaw sampling */ + +#define bat_to_device(x) ((x) * AUDIO_MAX_GAIN / MAX_AMP) +#define device_to_bat(x) ((x) * MAX_AMP / AUDIO_MAX_GAIN) + +/* Try to open the audio device. */ +/* Returns a valid file descriptor if ok, -1 otherwise. */ +int +audio_open(audio_format format) +{ + audio_info_t tmp_info; + + int audio_fd = open("/dev/audio", O_RDWR | O_NDELAY); + + if (audio_fd > 0) { + AUDIO_INITINFO(&dev_info); + dev_info.monitor_gain = 0; + dev_info.play.sample_rate = format.sample_rate; + dev_info.record.sample_rate = format.sample_rate; + dev_info.play.channels = format.num_channels; + dev_info.record.channels = format.num_channels; + dev_info.play.precision = format.bits_per_sample; + dev_info.record.precision = format.bits_per_sample; + dev_info.play.gain = (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN) * 0.75; + dev_info.record.gain = (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN) * 0.75; + dev_info.play.port = AUDIO_HEADPHONE; + dev_info.record.port = AUDIO_MICROPHONE; + dev_info.play.balance = AUDIO_MID_BALANCE; + dev_info.record.balance = AUDIO_MID_BALANCE; +#ifdef SunOS_5 + dev_info.play.buffer_size = DEVICE_BUF_UNIT; + dev_info.record.buffer_size = DEVICE_BUF_UNIT; +#endif + switch (format.encoding) { + case DEV_PCMU: + dev_info.record.encoding = AUDIO_ENCODING_ULAW; + dev_info.play.encoding = AUDIO_ENCODING_ULAW; + break; + case DEV_L8: + assert(format.bits_per_sample == 8); + dev_info.record.encoding = AUDIO_ENCODING_LINEAR; + dev_info.play.encoding = AUDIO_ENCODING_LINEAR; + break; + case DEV_L16: + assert(format.bits_per_sample == 16); + dev_info.record.encoding = AUDIO_ENCODING_LINEAR; + dev_info.play.encoding = AUDIO_ENCODING_LINEAR; + break; + default: + printf("ERROR: Unknown audio encoding in audio_open!\n"); + abort(); + } + + memcpy(&tmp_info, &dev_info, sizeof(audio_info_t)); + if (ioctl(audio_fd, AUDIO_SETINFO, (caddr_t)&tmp_info) < 0) { + if (format.encoding == DEV_L16) { +#ifdef DEBUG + printf("Old hardware detected: can't do 16 bit audio, trying 8 bit...\n"); +#endif + dev_info.play.precision = 8; + dev_info.record.precision = 8; + dev_info.record.encoding = AUDIO_ENCODING_ULAW; + dev_info.play.encoding = AUDIO_ENCODING_ULAW; + if (ioctl(audio_fd, AUDIO_SETINFO, (caddr_t)&dev_info) < 0) { + perror("Setting MULAW audio paramterts"); + return -1; + } + mulaw_device = TRUE; + } else { + perror("Setting audio paramterts"); + return -1; + } + } + return audio_fd; + } else { + /* Because we opened the device with O_NDELAY + * the waiting flag was not updated so update + * it manually using the audioctl device... + */ + audio_fd = open("/dev/audioctl", O_RDWR); + AUDIO_INITINFO(&dev_info); + dev_info.play.waiting = 1; + if (ioctl(audio_fd, AUDIO_SETINFO, (caddr_t)&dev_info) < 0) { +#ifdef DEBUG + perror("Setting requests"); +#endif + } + close(audio_fd); + return -1; + } +} + +/* Close the audio device */ +void +audio_close(int audio_fd) +{ + close(audio_fd); + audio_fd = -1; +} + +/* Flush input buffer */ +void +audio_drain(int audio_fd) +{ + ioctl(audio_fd, AUDIO_FLUSH, 0); +} + +/* Gain and volume values are in the range 0 - MAX_AMP */ + +void +audio_set_gain(int audio_fd, int gain) +{ + if (audio_fd <= 0) + return; + + AUDIO_INITINFO(&dev_info); + dev_info.record.gain = bat_to_device(gain); + if (ioctl(audio_fd, AUDIO_SETINFO, (caddr_t)&dev_info) < 0) + perror("Setting gain"); +} + +int +audio_get_gain(int audio_fd) +{ + if (audio_fd <= 0) + return (0); + + AUDIO_INITINFO(&dev_info); + if (ioctl(audio_fd, AUDIO_GETINFO, (caddr_t)&dev_info) < 0) + perror("Getting gain"); + return (device_to_bat(dev_info.record.gain)); +} + +void +audio_set_volume(int audio_fd, int vol) +{ + if (audio_fd <= 0) + return; + + AUDIO_INITINFO(&dev_info); + dev_info.play.gain = bat_to_device(vol); + if (ioctl(audio_fd, AUDIO_SETINFO, (caddr_t)&dev_info) < 0) + perror("Setting volume"); +} + +int +audio_get_volume(int audio_fd) +{ + if (audio_fd <= 0) + return (0); + + AUDIO_INITINFO(&dev_info); + if (ioctl(audio_fd, AUDIO_GETINFO, (caddr_t)&dev_info) < 0) + perror("Getting gain"); + return (device_to_bat(dev_info.play.gain)); +} + +int +audio_read(int audio_fd, sample *buf, int samples) +{ + int i, len; + static u_char mulaw_buf[DEVICE_REC_BUF]; + u_char *p; + + if (mulaw_device) { + if ((len = read(audio_fd, mulaw_buf, samples)) < 0) { + return 0; + } else { + p = mulaw_buf; + for (i = 0; i < len; i++) { + *buf++ = u2s((unsigned)*p); + p++; + } + return (len); + } + } else { + if ((len = read(audio_fd, (char *)buf, samples * BYTES_PER_SAMPLE)) < 0) { + return 0; + } else { + return (len / BYTES_PER_SAMPLE); + } + } +} + +int +audio_write(int audio_fd, sample *buf, int samples) +{ + int i, done, len, bps; + unsigned char *p, *q; + static u_char mulaw_buf[DEVICE_REC_BUF]; + + if (mulaw_device) { + p = mulaw_buf; + for (i = 0; i < samples; i++) + *p++ = lintomulaw[(unsigned short)*buf++]; + p = mulaw_buf; + len = samples; + bps = 1; + } else { + p = (char *)buf; + len = samples * BYTES_PER_SAMPLE; + bps = BYTES_PER_SAMPLE; + } + + q = p; + while (1) { + if ((done = write(audio_fd, p, len)) == len) + break; + if (errno != EINTR) + return (samples - ((len - done) / bps)); + len -= done; + p += done; + } + + return (samples); +} + +/* Set ops on audio device to be non-blocking */ +void +audio_non_block(int audio_fd) +{ + int on = 1; + + if (audio_fd <= 0) + return; + + if (ioctl(audio_fd, FIONBIO, (char *)&on) < 0) + fprintf(stderr, "Failed to set non blocking mode on audio device!\n"); +} + +/* Set ops on audio device to block */ +void +audio_block(int audio_fd) +{ + int on = 0; + + if (audio_fd <= 0) + return; + + if (ioctl(audio_fd, FIONBIO, (char *)&on) < 0) + fprintf(stderr, "Failed to set blocking mode on audio device!\n"); +} + +void +audio_set_oport(int audio_fd, int port) +{ + if (audio_fd <= 0) + return; + + AUDIO_INITINFO(&dev_info); + /* AUDIO_SPEAKER or AUDIO_HEADPHONE */ + dev_info.play.port = port; + if (ioctl(audio_fd, AUDIO_SETINFO, (caddr_t)&dev_info) < 0) + perror("Setting port"); +} + +int +audio_get_oport(int audio_fd) +{ + if (audio_fd <= 0) + return (AUDIO_SPEAKER); + + AUDIO_INITINFO(&dev_info); + if (ioctl(audio_fd, AUDIO_GETINFO, (caddr_t)&dev_info) < 0) + perror("Getting port"); + return (dev_info.play.port); +} + +int +audio_next_oport(int audio_fd) +{ + int port; + + if (audio_fd <= 0) + return (AUDIO_SPEAKER); + + AUDIO_INITINFO(&dev_info); + if (ioctl(audio_fd, AUDIO_GETINFO, (caddr_t)&dev_info) < 0) + perror("Getting port"); + + + port = dev_info.play.port; + port <<= 1; + + /* It is either wrong on some machines or i got something wrong! */ + if (dev_info.play.avail_ports < 3) + dev_info.play.avail_ports = 3; + + if ((port & dev_info.play.avail_ports) == 0) + port = 1; + + AUDIO_INITINFO(&dev_info); + dev_info.play.port = port; + if (ioctl(audio_fd, AUDIO_SETINFO, (caddr_t)&dev_info) < 0) + perror("Setting port"); + + return (port); +} + +void +audio_set_iport(int audio_fd, int port) +{ + if (audio_fd <= 0) + return; + + AUDIO_INITINFO(&dev_info); + dev_info.record.port = port; + if (ioctl(audio_fd, AUDIO_SETINFO, (caddr_t)&dev_info) < 0) + perror("Setting port"); +} + +int +audio_get_iport(int audio_fd) +{ + if (audio_fd <= 0) + return (AUDIO_SPEAKER); + + AUDIO_INITINFO(&dev_info); + if (ioctl(audio_fd, AUDIO_GETINFO, (caddr_t)&dev_info) < 0) + perror("Getting port"); + return (dev_info.record.port); +} + +int +audio_next_iport(int audio_fd) +{ + int port; + + if (audio_fd <= 0) + return (AUDIO_SPEAKER); + + AUDIO_INITINFO(&dev_info); + if (ioctl(audio_fd, AUDIO_GETINFO, (caddr_t)&dev_info) < 0) + perror("Getting port"); + + port = dev_info.record.port; + port <<= 1; + + if (dev_info.record.avail_ports > 3) + dev_info.record.avail_ports = 3; + + /* Hack to fix Sparc 5 SOLARIS bug */ + if ((port & dev_info.record.avail_ports) == 0) + port = 1; + + AUDIO_INITINFO(&dev_info); + dev_info.record.port = port; + if (ioctl(audio_fd, AUDIO_SETINFO, (caddr_t)&dev_info) < 0) + perror("Setting port"); + + return (port); +} + +void +audio_switch_out(int audio_fd, cushion_struct *ap) +{ + /* Full duplex device: do nothing! */ +} + +void +audio_switch_in(int audio_fd) +{ + /* Full duplex device: do nothing! */ +} + +int +audio_duplex(int audio_fd) +{ + return 1; +} + +#endif /* __NetBSD__ */ +