1 /*
2 * audio-oss.cc --
3 *
4 * Audio driver for OSS (Open Sound) API, which is primarily
5 * used on FreeBSD and Linux.
6 */
7
8 /*
9 * Full Duplex audio module for the new sound driver and full duplex
10 * cards. Luigi Rizzo, from original sources supplied by Amancio Hasty.
11 *
12 * This includes some enhancements:
13 * - limit the maximum size of the playout queue to approx 4 frames;
14 * this is necessary if the write channel is slower than expected;
15 * the fix is based on two new ioctls, AIOGCAP and AIONWRITE,
16 * but the code should compile with the old driver as well.
17 * - use whatever format is available from the card (included split
18 * format e.g. for the sb16);
19 */
20
21 #ifdef __FreeBSD__
22 /* included for __FreeBSD_version */
23 # include <sys/param.h>
24 # if (__FreeBSD_version >= 400000)
25 # include <sys/soundcard.h>
26 # else
27 # include <machine/soundcard.h>
28 # endif
29 #else
30 # include <sys/soundcard.h>
31 #endif
32
33 //#include <osfcn.h>
34 #include <fcntl.h>
35 #include "mulaw.h"
36 #include "tclcl.h"
37 #include "audio-oss.h"
38
39 #define ULAW_ZERO 0x7f
40 #define ABUFLOG2 7
41 #define ABUFLEN ( 1<< ABUFLOG2)
42 #define NFRAG 5
43 #define NDRVRBUF 5
44
45 // this is the OTcl wrapper to make the C++ object a Tcl class
46 static class OSSAudioClass : public TclClass {
47 public:
48 OSSAudioClass() : TclClass("Audio/OSS") {}
49 TclObject* create(int, const char*const*) {
50 return (new OSSAudio);
51
52 }
53 } oss_audio_class;
54
55 OSSAudio::OSSAudio() : mixerfd(-1)
56 {
57 // the "*2" is because we want to accomodate 16 bit samples as well as 8.
58 readbuf = new u_char[ABUFLEN*NDRVRBUF*2];
59 s16_buf = new u_short[blksize_];
60 readCopyInPtr = readbuf;
61 readCopyOutPtr = readbuf;
62
63 //typically we will be using 8 bit samples in u-law mode...
64 memset(readbuf, ULAW_ZERO, blksize_);
65
66 /*
67 * The only way to determine if the device is full duplex
68 * or not is by actually opening it. Unfortunately, we might
69 * not be able to open it because some other process is
70 * using it. Assume half-duplex. Obtain() will override
71 * if appropriate.
72 */
73 duplex_ = 0;
74
75 input_names_ = "mike linein cd";
76 output_names_ = "speaker lineout";
77 played=0;
78 playedDuringLast=0;
79 sample_rate = 8000; // default value is 8K
80 use16RawPCM = 0; // default value is to use 8 bit mulaw...
81 stereo = 0; // default value is mono
82 }
83
84 void
85 OSSAudio::Obtain()
86 {
87 char *thedev;
88 char buf[64];
89 int d = -1;
90 int capabilities = 0;
91 played=0;
92
93 if (haveaudio())
94 return;
95
96 // get ready to open the audio device
97 if(device_ < 0)
98 {
99 thedev=getenv("AUDIODEV");
100 if (thedev==NULL)
101 thedev="/dev/audio";
102 else if (thedev[0]>='') {
103 d = atoi(thedev);
104 sprintf(buf,"/dev/audio%d", d);
105 thedev = buf ;
106 }
107 }
108 else
109 {
110 d = device_;
111 sprintf(buf, "/dev/audio%d", d);
112 thedev = buf;
113 }
114 // open the audio device
115 #if 0
116 fd_ = open(thedev, O_WRONLY);
117 ioctl(fd_, SNDCTL_DSP_GETCAPS, &capabilities);
118 if (capabilities & DSP_CAP_DUPLEX) {
119 close(fd_);
120 #endif
121 fd_ = open(thedev, O_RDWR);
122 #if 0
123 }
124 #endif
125
126 // get ready to open the mixer
127 if(device_ < 0)
128 {
129 thedev=getenv("MIXERDEV");
130 if (thedev == NULL)
131 {
132 if (d < 0)
133 thedev = "/dev/mixer";
134 else {
135 sprintf(buf,"/dev/mixer%d", d);
136 thedev = buf ;
137 }
138 }
139 }
140 else
141 {
142 sprintf(buf,"/dev/mixer%d", d);
143 thedev = buf ;
144 }
145 // open the mixer
146 mixerfd = open(thedev, O_RDWR); // O_NDELAY
147
148 // check for errors in opening the device
149 if(fd_ <0 ) {
150 printf("couldn't open audio device\n");
151 // retry using read only(?)
152 // -- if so, then will need to track the last mode that was used
153 }
154 if(mixerfd <0 )
155 printf("couldn't open mixer device\n");
156
157 if (fd_ >= 0) {
158 // do the IOCTL to control the audio device and mixer
159 int channels = stereo+1;
160 int rec_rate=sample_rate;
161 int formats=0;
162 int playformat=0, recordformat=0;
163 int ret1=0;
164 #ifdef SNDCTL_DSP_CHANNELS
165 ret1=ioctl(fd_, SNDCTL_DSP_CHANNELS, &channels);
166 #else
167 if (channels == 2)
168 ret1=ioctl(fd_, SNDCTL_DSP_STEREO, &channels);
169 #endif
170 if(ret1<0) {
171 perror("failed to set number of channels correctly");
172 }
173 ret1=ioctl(fd_, SNDCTL_DSP_SPEED, &rec_rate);
174 if(ret1<0) {
175 perror("failed to set sampling rate");
176 }
177 capabilities=0;
178 if (ioctl(fd_, SNDCTL_DSP_GETCAPS, &capabilities) <0) {
179 perror("failed to get capabilities");
180 }
181 if( ioctl(fd_, SNDCTL_DSP_GETFMTS, &formats) <0) {
182 perror("failed to get formats");
183 }
184
185 int sources=0;
186 if ( ioctl(mixerfd, SOUND_MIXER_READ_DEVMASK, &sources) == -1 ) {
187 perror("failed to poll inputs");
188 }
189
190 if(!(sources & (1 << SOUND_MIXER_RECLEV))) {
191 vol_device=SOUND_MIXER_IGAIN;
192 }
193 else vol_device=SOUND_MIXER_RECLEV;
194
195 switch (capabilities & (DSP_CAP_DUPLEX) ) {
196 case DSP_CAP_DUPLEX :
197 #ifdef AFMT_WEIRD
198 if(formats & AFMT_WEIRD) { /* this is the sb16... */
199 if (formats & AFMT_S16_LE) {
200 playformat = AFMT_U8 ;
201 recordformat = AFMT_S16_LE;
202 } else {
203 printf("sorry, no supported formats\n");
204 close(fd_);
205 close(mixerfd);
206 fd_ = -1 ;
207 return;
208 }
209 }
210 else { // well-behaved soundcard
211 #endif
212 /*
213 * this entry for cards with decent full duplex. Use s16
214 * preferably (some are broken in ulaw) or ulaw or u8 otherwise.
215 */
216 if (formats & AFMT_S16_LE)
217 playformat = recordformat = AFMT_S16_LE ;
218 else if (formats & AFMT_MU_LAW)
219 playformat = recordformat = AFMT_MU_LAW ;
220 else if (formats & AFMT_U8)
221 playformat = recordformat = AFMT_U8 ;
222 else {
223 printf("sorry, no supported formats\n");
224 close(fd_);
225 close(mixerfd);
226 fd_ = -1 ;
227 return;
228 }
229 #ifdef AFMT_WEIRD
230 }
231 #endif
232 if ((playformat != AFMT_S16_LE) && (use16RawPCM == 1))
233 printf("sorry, can't do 16 bit samples with this sound card...\n");
234 break ;
235
236 default :
237 // start of new section
238 //printf("sorry don't know how to deal with this card\n");
239 /*
240 * this entry for cards with half duplex. Use s16
241 * preferably (some are broken in ulaw) or ulaw or u8 otherwise.
242 */
243 if (formats & AFMT_S16_LE)
244 playformat = recordformat = AFMT_S16_LE ;
245 else if (formats & AFMT_MU_LAW)
246 playformat = recordformat = AFMT_MU_LAW ;
247 else if (formats & AFMT_U8)
248 playformat = recordformat = AFMT_U8 ;
249 else {
250 printf("sorry, no supported formats\n");
251 // end of new section
252 close (fd_);
253 close(mixerfd);
254 fd_ = -1;
255 // start of new section
256 }
257 // end of new section
258 if ((playformat != AFMT_S16_LE) && (use16RawPCM == 1))
259 printf("sorry, can't do 16 bit samples with this sound card...\n");
260 break;
261 }
262
263 #ifdef AIOSFMT
264 if(playformat!=recordformat) {
265 // printf("specifing two formats to your poor soundcard\n");
266 snd_chan_param params;
267 params.play_rate=sample_rate;
268 params.rec_rate=sample_rate;
269 params.play_format=playformat;
270 params.rec_format=recordformat;
271 int stat=ioctl(fd_, AIOSFMT, ¶ms);
272 if(stat<0) {
273 printf("dual-format specification failed\n");
274 }
275 }
276 else {
277 ioctl(fd_, SNDCTL_DSP_SETFMT, &playformat);
278 }
279 play_fmt=playformat;
280 rec_fmt=recordformat;
281 #else
282 if(playformat!=recordformat) {
283 printf("Different formats for playback and capture: binary not compiled for this\n");
284 close(fd_);
285 close(mixerfd);
286 fd_=-1;
287 return;
288 }
289 ioctl(fd_, SNDCTL_DSP_SETFMT, &playformat);
290 play_fmt=playformat;
291 rec_fmt=recordformat;
292 #endif
293
294 int frag= (NFRAG << 16) | ABUFLOG2;
295 int ret=ioctl(fd_, SNDCTL_DSP_SETFRAGMENT, &frag);
296
297 duplex_ = (capabilities & DSP_CAP_DUPLEX) ? 1:0;
298
299 /*
300 * Set the line input level to 0 to shut
301 * off the analog side-tone gain between
302 * the line-in and line-out. This would otherwise
303 * wreak havoc on an echo canceler, for example,
304 * plugged into the audio adaptor.
305 */
306 int v = 0;
307 ret=ioctl(mixerfd, MIXER_WRITE(SOUND_MIXER_LINE), &v);
308 ret=ioctl(mixerfd, MIXER_WRITE(SOUND_MIXER_MIC), &v);
309 if( sources & (1 << SOUND_MIXER_DIGITAL1) ) {
310 ret=ioctl(mixerfd, MIXER_WRITE(SOUND_MIXER_DIGITAL1),&v);
311 }
312 if( sources & (1 << SOUND_MIXER_DIGITAL2) ) {
313 ret=ioctl(mixerfd, MIXER_WRITE(SOUND_MIXER_DIGITAL2),&v);
314 }
315 int device = 1 << SOUND_MIXER_MIC;
316 if ( ioctl(mixerfd, SOUND_MIXER_WRITE_RECSRC, &device) == -1 ) {
317 perror("failed to select input");
318 }
319
320 /*
321 * Restore the hardware settings in case
322 * some other vat changed them.
323 */
324
325 InputPort(iport_);
326 SetRGain(rgain_);
327 SetPGain(pgain_);
328
329 if (duplex_)
330 Audio::Obtain();
331 else
332 notify();
333 }
334 }
335
336
337 void OSSAudio::Release()
338 {
339 if (haveaudio()) {
340 if (mixerfd > 0) {
341 close(mixerfd);
342 }
343 mixerfd = -1;
344 Audio::Release();
345 }
346 }
347
348 // Called when you want to write audio out to the sound
349 // card. Called from within controller.cc
350 void OSSAudio::Write(u_char *cp)
351 {
352 // blksize_ is inherited from Audio parent class (audio.h/.cc)
353 // it is the number of samples NOT the size of the samples
354 unsigned int i = blksize_;
355 int l;
356
357 if (play_fmt == AFMT_S16_LE) {
358 if (use16RawPCM == 0) {
359 // translate it from 8 bit mulaw to 16 bit linear
360 for (i=0; i< blksize_; i++)
361 s16_buf[i] = mulawtolin[cp[i]] ;
362 cp = (u_char *)s16_buf;
363 }
364 // size goes from 8 bit to 16 bit, so you need to double i.
365 i = 2 *blksize_ ;
366 }
367 else if (play_fmt == AFMT_S8) {
368 for (i=0; i< blksize_; i++) {
369 int x = mulawtolin[cp[i]] ;
370 x = (x >> 8 ) & 0xff;
371 cp[i] = (u_char)x ;
372 }
373 i = blksize_ ;
374 } else if (play_fmt == AFMT_U8) {
375 for (i=0; i< blksize_; i++) {
376 int x = mulawtolin[cp[i]] ;
377 x = (x >> 8 ) & 0xff;
378 x = (x ^ 0x80) & 0xff ;
379 cp[i] = (u_char)x ;
380 }
381 i = blksize_ ;
382 }
383 played=1;
384 audio_buf_info info;
385 ioctl(fd_, SNDCTL_DSP_GETOSPACE,&info);
386 if(info.bytes>=(info.fragstotal*info.fragsize)-(info.fragsize>>1) ) {
387 if(playedDuringLast) { // adjusting for fast sound card
388 int locali=i/2;
389 unsigned char * localcp=cp;
390 for ( ; locali > 0 ; locali -= l) {
391 l = write(fd_, localcp, locali);
392 localcp += l;
393 }
394 } else { // would adjust, but haven't played during last
395 unsigned char buf[blksize_/2];
396 memset(buf,cp[0],blksize_/2);
397 write(fd_, buf, blksize_/2);
398 }
399 }
400 // write the audio data to the sound card.
401 for ( ; i > 0 ; i -= l) {
402 l = write(fd_, cp, i);
403 cp += l;
404 }
405 }
406
407 // The Read call is to read data in from the sound
408 // card (called in controller.cc). Basically it just
409 // reads from a ring buffer. The data is put into the
410 // buffer by FrameReady()
411 u_char* OSSAudio::Read()
412 {
413 playedDuringLast=played;
414 played=0;
415
416 u_char* ptr=readCopyOutPtr;
417 if (use16RawPCM == 0) {
418 // these are 8 bit samples
419 readCopyOutPtr+=blksize_;
420 // since it is 8 bit, we only use half the buffer
421 if(readCopyOutPtr>=readbuf+ABUFLEN*NDRVRBUF) {
422 if(readCopyOutPtr>readbuf+ABUFLEN*NDRVRBUF) {
423 printf("::read() pointer error: %d\n",
424 readCopyOutPtr-readbuf+ABUFLEN*NDRVRBUF );
425 }
426 readCopyOutPtr=readbuf;
427 }
428 } else {
429 // these are 16 bit samples, so we have blksize_ * 2 bytes
430 readCopyOutPtr+=(blksize_*2);
431 // since it is 16 bit samples, we use the whole buffer
432 if(readCopyOutPtr>=readbuf+(ABUFLEN*NDRVRBUF*2)) {
433 if(readCopyOutPtr>readbuf+(ABUFLEN*NDRVRBUF*2)) {
434 printf("::read() pointer error: %d\n",
435 readCopyOutPtr-readbuf+(ABUFLEN*NDRVRBUF*2));
436 }
437 readCopyOutPtr=readbuf;
438 }
439 }
440 return ptr;
441 }
442
443 /*
444 * In most mixer devices, there is only a master volume control on
445 * the capture channel, so the following code does not really work
446 * as expected. The only (partial) exception is the MIC line, where
447 * there is generally a 20dB boost which can be enabled or not
448 * depending on the type of device.
449 */
450 void OSSAudio::SetRGain(int level)
451 {
452 // start of new section
453 /* if (!haveaudio())
454 Obtain(); */
455 // end of new section
456
457 rgain_ = level;
458 float x = level;
459 level = (int) (x/2.56);
460 int foo = (level<<8) | level;
461 switch (iport_) {
462 case 2:
463 if (ioctl(mixerfd, MIXER_WRITE(vol_device), &foo) == -1)
464 perror("failed set input line volume for 2");
465 break;
466 case 1:
467 if (ioctl(mixerfd, MIXER_WRITE(vol_device), &foo) == -1)
468 perror("failed set input line volume for 1");
469 break;
470 case 0:
471 if (ioctl(mixerfd, MIXER_WRITE(vol_device), &foo) == -1)
472 perror("failed set input line volume for 0");
473 break;
474 }
475 }
476
477 // set the playback gain (volume)
478 void OSSAudio::SetPGain(int level)
479 {
480 // start of new section
481 /* if (!haveaudio())
482 Obtain(); */
483 // end of new section
484 pgain_ = level;
485 float x = level;
486 level = (int) (x/2.56);
487 int foo = (level<<8) | level;
488 if (mixerfd >= 0) {
489 if (ioctl(mixerfd, MIXER_WRITE(SOUND_MIXER_PCM), &foo) == -1) {
490 perror("failed to output level");
491 }
492 }
493 }
494
495 void OSSAudio::OutputPort(int p)
496 {
497 oport_ = p;
498 }
499
500 void OSSAudio::InputPort(int p)
501 {
502 int zero = 0;
503
504 switch(p) {
505 case 2:
506 zero = 1 << SOUND_MIXER_CD;
507 break;
508 case 1:
509 zero = 1 << SOUND_MIXER_LINE;
510 break;
511 case 0 :
512 zero = 1 << SOUND_MIXER_MIC;
513 break;
514 }
515 int i=0;
516 if ( ioctl(mixerfd, SOUND_MIXER_READ_DEVMASK, &i) == -1 ) {
517 perror("failed to select input");
518 p = 0;
519 }
520 if ( ioctl(mixerfd, SOUND_MIXER_READ_RECMASK, &i) == -1 ) {
521 perror("failed to select input");
522 p = 0;
523 }
524 if ( ioctl(mixerfd, SOUND_MIXER_READ_RECSRC, &i) == -1 ) {
525 perror("failed to select input");
526 p = 0;
527 }
528 if ( ioctl(mixerfd, SOUND_MIXER_WRITE_RECSRC, &zero) == -1 ) {
529 perror("failed to select input");
530 p = 0;
531 }
532 iport_ = p;
533 if ( ioctl(mixerfd, SOUND_MIXER_READ_RECSRC, &i) == -1 ) {
534 perror("failed to select input");
535 p = 0;
536 }
537 }
538
539 /*
540 * FrameReady must return 0 every so often, or the system will keep
541 * processing mike data and not other events. This function is called
542 * by Audio::dispatch() and if it returns 1 then dispatch will go on
543 * to call Controller::handle_audio(). Basically, this function gets
544 * audio data from the sound card and stores it in a ring buffer (which
545 * is read when the Read() function is called). It returns when there is
546 * a full frame of audio data ready.
547 */
548 int OSSAudio::FrameReady()
549 {
550 if (rec_fmt == AFMT_S16_LE) {
551 if (use16RawPCM == 0) {
552 // we want to store 8 bit mulaw audio in the ring buffer.
553 u_short s16Buffer[ABUFLEN];
554 if( read(fd_, (u_char*)s16Buffer, ABUFLEN) != (int)(ABUFLEN)) {
555 // there isn't a full buffer of audio yet, keep waiting...
556 perror("sound device read");
557 } else {
558 // translate it from 16 bit linear to 8 bit mulaw
559 for (int i=0; i< (int)ABUFLEN>>1; i++) {
560 readCopyInPtr[i] = lintomulaw[ s16Buffer[i] & 0xffff ] ;
561 }
562 readCopyInPtr+=(ABUFLEN>>1);
563 // write it to the ring buffer
564 if(readCopyInPtr>=readbuf+ABUFLEN*NDRVRBUF) {
565 if(readCopyInPtr>readbuf+ABUFLEN*NDRVRBUF) {
566 printf("ossaudio::frameready pointer error by %d\n",
567 readCopyInPtr-readbuf+ABUFLEN*NDRVRBUF);
568 }
569 readCopyInPtr=readbuf;
570 }
571 }
572 } else {
573 // we want to store 16 bit linear audio in the ring buffer.
574 if( read(fd_, (u_char*)readCopyInPtr, ABUFLEN) != (int)(ABUFLEN)) {
575 // there isn't a full buffer of audio yet, keep waiting...
576 perror("sound device read");
577 } else
578 readCopyInPtr+=ABUFLEN;
579 // store it in the ring buffer
580 if(readCopyInPtr>=readbuf+(ABUFLEN*NDRVRBUF*2)) {
581 if(readCopyInPtr>readbuf+(ABUFLEN*NDRVRBUF*2)) {
582 printf("ossaudio::frameready pointer error by %d\n",
583 readCopyInPtr-readbuf+(ABUFLEN*NDRVRBUF*2));
584 }
585 readCopyInPtr=readbuf;
586 }
587 }
588 } else {
589 // here we are dealing with legacy 8 bit cards...
590 if( read(fd_, readCopyInPtr, ABUFLEN) != (int)(ABUFLEN) ) {
591 perror("sound device read");
592 }
593 else {
594 if (rec_fmt == AFMT_S8) {
595 int i;
596 for (i=0; i< (int)ABUFLEN; i++) {
597 readCopyInPtr[i] = lintomulaw[ readCopyInPtr[i]<<8 ] ;
598 }
599 }
600 else if (rec_fmt == AFMT_U8) {
601 for (int i=0; i< (int)ABUFLEN; i++) {
602 readCopyInPtr[i] = lintomulaw[ (readCopyInPtr[i]<<8) ^ 0x8000 ] ;
603 }
604 }
605 readCopyInPtr+=ABUFLEN;
606 if(readCopyInPtr>=readbuf+ABUFLEN*NDRVRBUF)
607 readCopyInPtr=readbuf;
608 }
609 }
610
611 int ret;
612
613 // return value is dependant on how much data we have saved up...
614 if( (unsigned int)(readCopyInPtr)>=(unsigned int)(readCopyOutPtr) ) {
615 // if the data doesn't wrap around the end of the buffer
616 if (use16RawPCM == 1)
617 // wait for a 16 bit frame
618 ret= ( (unsigned int)(readCopyInPtr)-(unsigned int)(readCopyOutPtr)>=(blksize_*2));
619 else
620 // wait for an 8 bit frame
621 ret= ( (unsigned int)(readCopyInPtr)-(unsigned int)(readCopyOutPtr)>=blksize_);
622 return ret;
623 }
624 else {
625 // the data wraps around the end of the buffer...
626 if (use16RawPCM == 1)
627 // wait for a 16 bit frame
628 ret=((readbuf+(ABUFLEN*NDRVRBUF*2)-readCopyOutPtr+readCopyInPtr-readbuf)
629 >=(int)(blksize_*2));
630 else
631 // wait for an 8 bit frame
632 ret=((readbuf+ABUFLEN*NDRVRBUF-readCopyOutPtr+readCopyInPtr-readbuf)
633 >=(int)blksize_);
634 return ret;
635 }
636 }
637
638 // commands that allow control from Tcl code
639 int OSSAudio::command(int argc, const char*const* argv)
640 {
641 Tcl& tcl = Tcl::instance();
642 if (argc == 2) {
643 if (strcmp(argv[1], "useRaw16PCM") == 0) {
644 use16RawPCM = 1;
645 return (TCL_OK);
646 }
647 if (strcmp(argv[1], "useStereo") == 0) {
648 stereo = 1;
649 return (TCL_OK);
650 }
651 if (strcmp(argv[1], "in16bitMode") == 0) {
652 sprintf(tcl.result(), "%d", use16RawPCM);
653 return (TCL_OK);
654 }
655 if (strcmp(argv[1], "inStereoMode") == 0) {
656 sprintf(tcl.result(), "%d", stereo);
657 return (TCL_OK);
658 }
659 if (strcmp(argv[1], "getSampleRate") == 0) {
660 sprintf(tcl.result(), "%d", sample_rate);
661 return (TCL_OK);
662 }
663 }
664 if (argc == 3) {
665 if (strcmp(argv[1], "set_sample_rate") == 0) {
666 sample_rate = atoi(argv[2]);
667 return (TCL_OK);
668 }
669 }
670 return (Audio::command(argc,argv));
671 }
672
673
674
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.