/* * 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. */ #ifndef lint static const char rcsid[] = "@(#) $Header: audio-pc.cc,v 1.7 96/04/26 04:06:56 van Exp $ (LBL)"; #endif #include /* XXX */ #include class PCAudio : public Audio { public: PCAudio(); virtual int FrameReady(); virtual u_char* Read(); virtual void Write(u_char *); virtual void SetRGain(int); virtual void SetPGain(int); virtual void OutputPort(int); virtual void InputPort(int); virtual void Obtain(); virtual void Release(); virtual void RMute(); virtual void RUnmute(); protected: int setinfo(struct audio_info*); int getinfo(struct audio_info*); int GainClip(int); int OPort(int); int IPort(int); void* state; u_char* buffer; }; static class PCAudioMatcher : : public Matcher { public: PCAudioMatcher() : Matcher("audio") {} TclObject* match(const char* fmt) { if (strcmp(fmt, "pc") == 0) return (new PCAudio); return (0); } } pc_audio_matcher; PCAudio::PCAudio() { state = new audio_info_t; AUDIO_INITINFO((audio_info_t*)state); buffer = new u_char[blksize]; } int PCAudio::OPort(int p) { switch(p) { default: case output_speaker: return (AUDIO_SPEAKER); case output_phones: return (AUDIO_HEADPHONE); } } int PCAudio::IPort(int p) { /*XXX*/ return (0); } void PCAudio::Release() { if (fd >= 0) { getinfo((audio_info_t*)state); Audio::Release(); } } void PCAudio::Obtain() { if (HaveAudio()) abort(); fd = open("/dev/audio", O_RDWR|O_NDELAY); if (fd >= 0) { int on = 1; ioctl(fd, FIONBIO, &on); audio_info_t* i = (audio_info_t*)state; getinfo(i); i->record.gain = rgain; i->play.gain = pgain; i->play.port = OPort(oport); i->blocksize = blksize; i->mode = AUMODE_RECORD; setinfo(i); Audio::Obtain(); } } void PCAudio::Write(u_char *cp) { register int len = blksize; int cc = write(fd, (char *)cp, len); if ((len -= cc) != 0) { do { if (cc < 0) { if (errno != EPERM) perror("audio write"); return; } cp += cc; cc = write(fd, (char *)cp, len); len -= cc; } while (len > 0); } } int PCAudio::FrameReady() { /* the bsd audio driver does reads in blksize chunks */ int cc = read(fd, (char *)buffer, blksize); if (cc <= 0) return (0); if (cc != blksize) fprintf(stderr, "vat: audio read %d (blksize %d)\n", cc, blksize); return (1); } u_char* PCAudio::Read() { return (buffer); } int PCAudio::GainClip(int level) { if (level < AUDIO_MIN_GAIN) return AUDIO_MIN_GAIN; else if (level > AUDIO_MAX_GAIN) return AUDIO_MAX_GAIN; else return level; } int PCAudio::getinfo(audio_info_t* info) { int sts; if (fd < 0) sts = 0; else sts = ioctl(fd, AUDIO_GETINFO, info); return (sts); } int PCAudio::setinfo(audio_info_t* info) { int sts; if (fd < 0) sts = 0; else sts = ioctl(fd, AUDIO_SETINFO, info); return (sts); } void PCAudio::SetRGain(int level) { audio_info_t info; rgain = GainClip(level); AUDIO_INITINFO(&info); info.record.gain = rgain; setinfo(&info); } void PCAudio::SetPGain(int level) { audio_info_t info; pgain = GainClip(level); AUDIO_INITINFO(&info); info.play.gain = pgain; setinfo(&info); } void PCAudio::OutputPort(int p) { audio_info_t info; oport = p; AUDIO_INITINFO(&info); info.play.port = OPort(p); setinfo(&info); } void PCAudio::InputPort(int p) { audio_info_t info; iport = p; AUDIO_INITINFO(&info); info.play.port = IPort(p); setinfo(&info); } void PCAudio::RMute() { rmute |= 1; audio_info_t* i = (audio_info_t*)state; i->mode = AUMODE_PLAY; setinfo(i); } void PCAudio::RUnmute() { rmute &=~ 1; audio_info_t* i = (audio_info_t*)state; i->mode = AUMODE_RECORD; setinfo(i); }