/* * Copyright (c) 1993-1994 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-sock.cc,v 1.14 96/04/26 04:08:15 van Exp $ (LBL)"; #endif #include #include #include #include #include #include #include #include #include "audio.h" #include "Tcl.h" class SocketAudio : public Audio { public: SocketAudio(const char *filename); virtual int FrameReady(); virtual u_char* Read(); virtual void Write(u_char *); virtual void Obtain(); virtual void Release(); protected: u_char* buf_; u_char* bufcur_; u_char* bufend_; sockaddr_un sockaddr_; int socklen_; int lock_; }; static class SocketAudioMatcher : public Matcher { public: SocketAudioMatcher() : Matcher("audio") {} TclObject* match(const char* id) { /* XXX assume socket pathname starts with slash */ if (*id == '/') return (new SocketAudio(id)); else return (0); } } socket_audio_matcher; SocketAudio::SocketAudio(const char *name) { sockaddr_.sun_family = AF_UNIX; strcpy(sockaddr_.sun_path, name); socklen_ = strlen(sockaddr_.sun_path) + 2; bufcur_ = buf_ = new u_char[blksize]; bufend_ = buf_ + blksize; openlock(); } void SocketAudio::Release() { if (HaveAudio()) { unlock(); Audio::Release(); } } void SocketAudio::Obtain() { if (HaveAudio()) abort(); if (lock() == 0) { fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { perror("vat: socket"); exit(1); } if (connect(fd, (sockaddr*)&sockaddr_, socklen_) < 0) { if (errno != ECONNREFUSED && errno != ENOENT) perror("vat: audio connect"); close(fd); fd = -1; unlock(); return; } bufcur_ = buf_; Audio::Obtain(); } } void SocketAudio::Write(u_char *cp) { if (HaveAudio()) (void)write(fd, (char *)cp, blksize); } int SocketAudio::FrameReady() { register int len = bufend_ - bufcur_; while (len > 0) { int cc = read(fd, (char *)bufcur_, len); if (cc == 0) { Release(); return (0); } if (cc < 0) { switch (errno) { case EINVAL: /* probably wrapped file pos. */ lseek(fd, 0, SEEK_SET); cc = 0; break; case EPERM: /* probably lost audio */ goto out; case EWOULDBLOCK: /* should warn about audio_bsize here */ goto out; default: perror("vat: audio read"); return (0); } } bufcur_ += cc; len -= cc; } out: return (bufcur_ >= bufend_); } u_char* SocketAudio::Read() { bufcur_ = buf_; return (buf_); }