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
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.