~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Open Mash Cross Reference
mash/audio/audio-voxware.cc

Component: ~ [ mash ] ~ [ apps ] ~ [ gsm ] ~ [ lib ] ~ [ otcl ] ~ [ srm ] ~ [ tcl8.3 ] ~ [ tclcl ] ~ [ tk8.3 ] ~ [ tutorials ] ~

  1 /*
  2  * audio-voxware.cc --
  3  *
  4  *      FIXME: This file needs a description here.
  5  *
  6  * Copyright (c) 1991-2002 The Regents of the University of California.
  7  * All rights reserved.
  8  *
  9  * Redistribution and use in source and binary forms, with or without
 10  * modification, are permitted provided that the following conditions are met:
 11  *
 12  * A. Redistributions of source code must retain the above copyright notice,
 13  *    this list of conditions and the following disclaimer.
 14  * B. Redistributions in binary form must reproduce the above copyright notice,
 15  *    this list of conditions and the following disclaimer in the documentation
 16  *    and/or other materials provided with the distribution.
 17  * C. Neither the names of the copyright holders nor the names of its
 18  *    contributors may be used to endorse or promote products derived from this
 19  *    software without specific prior written permission.
 20  *
 21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
 22  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 23  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 31  * POSSIBILITY OF SUCH DAMAGE.
 32  */
 33 
 34 static const char rcsid[] =
 35     "@(#) $Header: /usr/mash/src/repository/mash/mash-1/audio/audio-voxware.cc,v 1.18 2002/02/03 03:10:46 lim Exp $";
 36 
 37 #include <string.h>
 38 #include <sys/fcntl.h>
 39 #include <errno.h>
 40 #if defined(sco) || defined(__bsdi__)
 41 #include <sys/socket.h>
 42 #endif
 43 #include <unistd.h>
 44 #if defined(__FreeBSD__)
 45 #include <sys/types.h>
 46 #include <sys/uio.h>
 47 #include <machine/soundcard.h>
 48 #else
 49 #include <sys/soundcard.h>
 50 #endif
 51 #include "audio.h"
 52 #include "tclcl.h"
 53 
 54 #define ULAW_ZERO 0x7f
 55 #define ABUFLOG2 7
 56 #define ABUFLEN (1 << ABUFLOG2)
 57 #define NFRAG 5
 58 
 59 #if defined(__bsdi__)
 60 #define BSD_SB_FIX
 61 #endif
 62 class VoxWareAudio : public Audio {
 63     public:
 64         VoxWareAudio();
 65         virtual int FrameReady();
 66         virtual u_char* Read();
 67         virtual void Write(u_char *);
 68         virtual void SetRGain(int);
 69         virtual void SetPGain(int);
 70         virtual void OutputPort(int);
 71         virtual void InputPort(int);
 72         virtual void Obtain();
 73         virtual void Release();
 74     protected:
 75 
 76         u_char* readptr;
 77         u_char* readbufend;
 78         u_char* readbuf;
 79 
 80         u_char* ubufptr;
 81         u_char* ubufend;
 82         u_char* ubuf;
 83 
 84         u_char* writeptr;
 85         u_char* writebufend;
 86         u_char* writebuf;
 87 
 88         int mixer;
 89 #ifdef BSD_SB_FIX
 90 #define NONE 0
 91 #define READ 1
 92 #define WRITE 2
 93         int lastop;       /* last operation: read or write */
 94 #endif /* BSD_SB_FIX */
 95 };
 96 
 97 static class VoxWareAudioClass : public TclClass {
 98     public:
 99         VoxWareAudioClass() : TclClass("Audio/VoxWare") {}
100         TclObject* create(int, const char*const*) {
101                 return (new VoxWareAudio);
102         }
103 } voxware_audio_class;
104 
105 VoxWareAudio::VoxWareAudio()
106         :mixer(-1)
107 {
108         /*FIXME assumes GUS PnP (or similar); should query this */
109         input_names_ = "mike linein";
110         output_names_ = "speaker";
111 
112         readbuf = new u_char[ABUFLEN];
113         readptr = readbufend = readbuf + ABUFLEN;
114 
115         writeptr = writebuf = new u_char[ABUFLEN];
116         writebufend = writebuf + ABUFLEN;
117 
118         ubufptr = ubuf = new u_char[blksize_];
119         ubufend = ubuf + blksize_;
120         memset(ubuf, ULAW_ZERO, blksize_);
121 
122         /*
123          * The only way to determine if the device is full duplex
124          * or not is by actually opening it.  Unfortunately, we might
125          * not be able to open it because some other process is
126          * using it.  Assume half-duplex.  Obtain() will override
127          * if appropriate.
128          */
129         duplex_ = 0;
130 #ifdef BSD_SB_FIX
131         lastop = NONE;
132 #endif /* BSD_SB_FIX */
133 }
134 
135 #if defined(__bsdi__)
136 
137 void VoxWareAudio::Obtain()
138 {
139         if (haveaudio())
140                 abort();
141 
142         fd_ = open("/dev/audio", O_RDWR|O_NDELAY);
143         if (fd_ >= 0) {
144                 int on = 1;
145                 ioctl(fd_, FIONBIO, &on);
146 
147                 int frag = (NFRAG << 16) | ABUFLOG2;
148                 ioctl(fd_, SNDCTL_DSP_SETFRAGMENT, &frag);
149 #ifdef fullduplex
150                 Audio::Obtain();
151 #else
152                 notify();
153 #endif
154         }
155 }
156 
157 #else
158 void VoxWareAudio::Obtain()
159 {
160         if (haveaudio())
161                 abort();
162 
163         fd_ = open("/dev/audio", O_RDWR|O_NDELAY);
164         if (fd_ >= 0) {
165                 mixer = open("/dev/mixer", O_RDWR);
166                 if (mixer < 0) {
167                         /*FIXME*/
168                         perror("/dev/mixer");
169                 }
170                 /*
171                  * Set non-blocking mode.  Have to do the driver
172                  * version as well.  FIXME is the FIONBIO really needed?
173                  */
174                 int on = 1;
175                 ioctl(fd_, FIONBIO, &on);
176                 on = 1;
177                 ioctl(fd_,SNDCTL_DSP_NONBLOCK , &on);
178 
179                 /*
180                  * Set up the DMA capture buffers.  The value in the
181                  * upper word is the maximum backlog in blocks
182                  * and the lower word is the (base 2 log of the)
183                  * block size.  Code in this module assumes this
184                  * block size is smaller than the frame size
185                  * used in the rest of vat (usually 160 samples so
186                  * ABUGLOG2 should be no larger than 7).
187                  */
188                 int frag = (NFRAG << 16) | ABUFLOG2;
189                 ioctl(fd_, SNDCTL_DSP_SETFRAGMENT, &frag);
190 
191                 /*
192                  * (re)set the speed in case someone else changed it
193                  */
194                 int speed = 8000;
195                 ioctl(fd_, SNDCTL_DSP_SPEED, &speed);
196 
197 #if defined(SNDCTL_DSP_GETCAPS)
198                 int info;
199                 if (ioctl(fd_, SNDCTL_DSP_GETCAPS, &info) < 0)
200                         duplex_ = 0;
201                 else
202                         duplex_ = (info & DSP_CAP_DUPLEX) ? 1 : 0;
203 #else
204                 duplex_ = 0;
205 #endif
206 
207                 /*
208                  * Set the line input level to 0 to shut
209                  * off the analog side-tone gain between
210                  * the line-in and line-out.  This would otherwise
211                  * wreak havoc on an echo canceler, for example,
212                  * plugged into the audio adaptor.
213                  */
214                 int v = 0;
215                 if (mixer > 0)
216                         (void)ioctl(mixer, MIXER_WRITE(SOUND_MIXER_LINE), &v);
217 
218                 /*
219                  * Restore the hardware settings in case
220                  * some other vat changed them.
221                  */
222                 SetRGain(rgain_);
223                 SetPGain(pgain_);
224                 InputPort(iport_);
225 
226                 /*FIXME*/
227                 if (duplex_)
228                         Audio::Obtain();
229                 else
230                         notify();
231         }
232 }
233 #endif
234 
235 void VoxWareAudio::Release()
236 {
237         if (haveaudio()) {
238                 if (mixer > 0)
239                         (void)close(mixer);
240                 mixer = -1;
241                 Audio::Release();
242         }
243 }
244 
245 
246 void VoxWareAudio::Write(u_char *cp)
247 {
248         register u_char *cpend = cp + blksize_;
249         register u_char *wbuf = writeptr;
250         register u_char *wend = writebufend;
251         for ( ; cp < cpend; cp += 4) {
252                 wbuf[0] = cp[0];
253                 wbuf[1] = cp[1];
254                 wbuf[2] = cp[2];
255                 wbuf[3] = cp[3];
256                 wbuf += 4;
257                 if (wbuf >= wend) {
258                         wbuf = writebuf;
259                         if (write(fd_, (char*)wbuf, ABUFLEN) != ABUFLEN)
260                                 perror("voxware aud write");
261                 }
262 #ifdef BSD_SB_FIX
263                 /*
264                  * close and reopen audio device when switching
265                  * from read to write.
266                  */
267                 if (lastop == READ) {
268                         Release();
269                         Obtain();
270                 }
271                 lastop = WRITE;
272 #endif /* BSD_SB_FIX */
273         }
274         writeptr = wbuf;
275 }
276 
277 int VoxWareAudio::FrameReady()
278 {
279         register u_char* cp = ubufptr;
280         register u_char* cpend = ubufend;
281         register u_char* rbuf = readptr;
282         register u_char* rend = readbufend;
283 
284         /*
285          * This loop assumes the output block size is
286          * larger than the read size (ABUFLEN).
287          */
288 #ifdef BSD_SB_FIX
289         /*
290          * close and reopen audio device when switching
291          * from read to write.
292          */
293         if (lastop == WRITE) {
294                 Release();
295                 Obtain();
296         }
297         lastop = READ;
298 #endif /* BSD_SB_FIX */
299         for ( ; cp < cpend; cp += 4) {
300                 if (rbuf >= rend) {
301                         rbuf = readbuf;
302                         int cc = read(fd_, (char*)rbuf, ABUFLEN);
303                         if (cc <= 0) {
304                                 ubufptr = cp;
305                                 readbufend = rbuf;
306                                 if (cc == -1 && errno != EAGAIN) {
307                                         Release();
308                                         Obtain();
309                                 }
310                                 return (0);
311                         }
312                         readbufend = rend = rbuf + cc;
313                 }
314                 cp[0] = rbuf[0];
315                 cp[1] = rbuf[1];
316                 cp[2] = rbuf[2];
317                 cp[3] = rbuf[3];
318                 rbuf += 4;
319         }
320         readptr = rbuf;
321         return (1);
322 }
323 
324 u_char* VoxWareAudio::Read()
325 {
326         u_char* cp = ubuf;
327         ubufptr = cp;
328         return (cp);
329 }
330 
331 void VoxWareAudio::SetRGain(int level)
332 {
333         rgain_ = level;
334         level = int(level / 2.56);
335         int v = level << 8 | level;
336         if (mixer >= 0 &&
337             ioctl(mixer, MIXER_WRITE(SOUND_MIXER_IGAIN), &v) < 0)
338                 perror("SOUND_MIXER_IGAIN");
339 }
340 
341 void VoxWareAudio::SetPGain(int level)
342 {
343         pgain_ = level;
344         level = int(level / 2.56);
345         int v = level << 8 | level;
346         if (mixer >= 0)
347                 (void)ioctl(mixer, MIXER_WRITE(SOUND_MIXER_PCM), &v);
348 }
349 
350 void VoxWareAudio::OutputPort(int p)
351 {
352         oport_ = p;
353 }
354 
355 void VoxWareAudio::InputPort(int p)
356 {
357         if (mixer >= 0) {
358                 /*
359                  * the port number is the positional index of the list
360                  * of input ports in input_names_
361                  */
362                 int mask = (p == 0) ?
363                         SOUND_MASK_MIC : SOUND_MASK_LINE;
364                 if (ioctl(mixer, MIXER_WRITE(SOUND_MIXER_RECSRC), &mask) < 0)
365                         perror("voxware ioctl: SOUND_MIXER_RECSRC");
366         }
367         iport_ = p;
368 }
369 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.