/* * Copyright (c) 1991-1993 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted 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 Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS 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 REGENTS 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. */ static const char rcsid[] = "@(#) $Header: audio-bsd.cc,v 1.16 96/03/16 13:12:46 van Exp $ (LBL)"; #include "audio-sun.h" #include #include #include #ifdef sun #include #else #include #endif class BSDAudio : public SUNAudio { public: inline BSDAudio(const char* device) : SUNAudio(device) {} virtual int FrameReady(); virtual u_char* Read(); virtual void Obtain(); virtual void Catchup(int); virtual int RDrops(); virtual int AdjustTime(u_int); virtual void Flush(); virtual int CanFilter() const { return 1; } virtual int outputs() const; protected: virtual int setinfo(struct audio_info*); virtual int getinfo(struct audio_info*); }; static class BSDAudioMatcher : public Matcher { public: BSDAudioMatcher() : Matcher("audio") {} TclObject* match(const char* id) { if (strcasecmp(id, "bsd") == 0) { Tcl& tcl = Tcl::instance(); const char* device = tcl.attr("audioFileName"); int i = -1;; if (strcmp(device, "/dev/audio") == 0 && (i = open("/dev/audioctl", O_RDONLY, 0)) < 0) return (new BSDAudio(device)); (void)close(i); } return (0); } } bsdaudio_matcher; void BSDAudio::Obtain() { if (HaveAudio()) abort(); fd = open(device_, O_RDWR|O_NDELAY); if (fd >= 0) { int on = 1; ioctl(fd, FIONBIO, (char*)&on); audio_info_t* i = (audio_info_t*)state; AUDIO_INITINFO((audio_info_t*)state); i->blocksize = blksize; i->record.gain = rgain; i->play.gain = pgain; i->play.port = oport? AUDIO_HEADPHONE : AUDIO_SPEAKER; setinfo(i); /* flush input to get rid of any data fragments */ Flush(); Audio::Obtain(); } } u_char* BSDAudio::Read() { u_char* cp = buf; register int len = blksize; int cc = read(fd, (char *)cp, len); if ((len -= cc) != 0) { do { if (cc < 0) { switch (errno) { case EINVAL: /* probably wrapped file pos. */ lseek(fd, 0, SEEK_SET); break; case EPERM: /* probably lost audio */ break; default: perror("audio read"); break; } break; } cp += cc; cc = read(fd, (char *)cp, len); len -= cc; } while (len > 0); } return (buf); } int BSDAudio::FrameReady() { return (1); } void BSDAudio::Catchup(int) { /* XXX This should happen only with a very busy system. */ printf("trying to catch up!\n"); exit(1); } int BSDAudio::RDrops() { int n; if (fd < 0 || ioctl(fd, AUDIO_RERROR, (char *)&n) < 0) n = -1; return (n); } int BSDAudio::getinfo(audio_info_t* info) { int sts; if (fd < 0) sts = 0; else sts = ioctl(fd, AUDIO_GETINFO, (char*)info); return (sts); } int BSDAudio::setinfo(audio_info_t* info) { int sts; if (fd < 0) sts = 0; else sts = ioctl(fd, AUDIO_SETINFO, (char*)info); return (sts); } /* * The time difference betwee now and when the audio last write * actually happens (i.e., when the last write actually starts * being output by the kernel). */ int BSDAudio::AdjustTime(u_int now) { u_long stamp; if (ioctl(fd, AUDIO_WSEEK, (char *)&stamp) < 0) { perror("AUDIO_WSEEK"); return (0); } return (stamp - now); } void BSDAudio::Flush() { if (ioctl(fd, AUDIO_FLUSH, (char *)0) < 0) { perror("AUDIO_FLUSH"); exit(1); } } int BSDAudio::outputs() const { return (2); }