#ifdef HAVE_SUN_AUDIOIO_H /* * Soundcard class for Solaris */ #include #include #include #include #include #include #include #include /* for ioctl(I_FLUSH) */ #include #include #include "sound.h" #include "sunaudio.h" #include "sunaudio.moc" /* ---------------------------------------------------------------------- */ Soundcard::Soundcard(char *dev) { if (dev) strcpy(devname,dev); else strcpy(devname,"/dev/audio"); strcpy(driver_name,"sunaudio"); get_capabilities(); channels = 1; rate = 16000; afmt = AUDIO_ENCODING_LINEAR; precision = 16; fd = -1; stat = STATUS_CLOSED; } Soundcard::~Soundcard() { stop(); } int Soundcard::start_record() { switch (stat) { case STATUS_CLOSED: if (!init_done) get_capabilities(); if (!init_done) return -1; return open_dev(TRUE); case STATUS_RECORD: return 0; case STATUS_PLAYBACK: close_dev(); return open_dev(TRUE); } return -1; } int Soundcard::start_playback() { switch (stat) { case STATUS_CLOSED: if (!init_done) get_capabilities(); if (!init_done) return -1; return open_dev(FALSE); case STATUS_RECORD: close_dev(); return open_dev(FALSE); case STATUS_PLAYBACK: return 0; } return -1; } int Soundcard::kill_buffer() { if(ioctl(fd, I_FLUSH, FLUSHRW)<0) { fprintf(stderr,"Sun audio error: could not flush queues: %s\n",strerror(errno)); return errno; } return 0; } int Soundcard::stop() { if (stat != STATUS_CLOSED) close_dev(); return 0; } /* ---------------------------------------------------------------------- */ void Soundcard::get_capabilities() { int dsp; audio_device_t audiotype; if (-1 != (dsp = open(devname, O_RDONLY))) { afmt_hw = -1; if (ioctl(dsp,AUDIO_GETDEV,&audiotype)<0) { fprintf(stderr,"Sun driver warning: could not determine audio device type\n"); } else { sprintf(driver_name,audiotype.name); DEBUG(printf("Sound driver recognized as ,,%s''\n",driver_name)); } if (!strcmp(audiotype.name,"SUNW,am79c30")) { // AMD 79C30 // 8bit mono ulaw 8kHz channels_hw = 1; afmt_hw = AUDIO_ENCODING_ULAW; precision_hw = 8; rate_hw = 8000; /* // if (tmp_precision==8)&&(tmp_channel==1)&&(tmp_rate==8000)) tmp_encoding=AUDIO_ENCODING_ULAW; fprintf(stderr,"ERROR: this program needs better soundcard\n"); else { fprintf(stderr,"Sound init error"); return 1; } */ } else if ((!strcmp(audiotype.name,"SUNW,CS4231"))|| (!strcmp(audiotype.name,"SUNW,dbri"))|| (!strcmp(audiotype.name,"speakerbox"))) { // CS 4231 or DBRI or speaker box // 16bit mono/stereo linear 8kHz - 48kHz channels_hw = 2; afmt_hw = AUDIO_ENCODING_LINEAR | AUDIO_ENCODING_ULAW; precision_hw = 16 | 8; rate_hw = 48000; /* if(tmp_precision==16) tmp_encoding=AUDIO_ENCODING_LINEAR; // 8bit mono ulaw 8kHz - 48kHz else if((tmp_precision==8)&&(tmp_channels==1)) tmp_encoding=AUDIO_ENCODING_ULAW; else { fprintf(stderr,"Sound init error"); return 1; } */ } if(afmt_hw==-1) { // if((tmp_precision==8)&&(tmp_stereo==1)&&(tmp_rate<=8000)) // play_encoding = AUDIO_ENCODING_ULAW; // else channels_hw = 2; precision_hw = 16 | 8; afmt_hw = AUDIO_ENCODING_LINEAR | AUDIO_ENCODING_ULAW; rate_hw = 48000; } close(dsp); init_done = 1; } else { init_done = 0; } } int Soundcard::has_channels() { if (!init_done) return -1; return channels_hw; } int Soundcard::has_format(int f) { if (!init_done) return -1; switch (f) { case FMT_8BIT: return (afmt_hw & AUDIO_ENCODING_ULAW) ? 1 : 0; break; case FMT_16BIT: return (afmt_hw & AUDIO_ENCODING_LINEAR) ? 1 : 0; case FMT_MULAW: case FMT_ALAW: default: return 0; } } char* Soundcard::driver() { return driver_name; } int Soundcard::open_dev(int record) { struct SOUNDPARAMS p; struct audio_info_t audioinfo; struct audio_prinfo_t *audiotype; if (-1 == (fd = open(devname,record ? O_RDONLY : O_WRONLY))) goto err; fcntl(fd,F_SETFD,FD_CLOEXEC); AUDIO_INITINFO(&audioinfo); audiotype = record ? &audioinfo.record : &audioinfo.play; audiotype->precision = precision; audiotype->channels = channels; audiotype->sample_rate = rate; audiotype->encoding = afmt; if (record) audiotype->port=AUDIO_MICROPHONE; // could be AUDIO_LINE_IN if(ioctl(fd,AUDIO_SETINFO,&audioinfo)<0) { fprintf(stderr,"Sun audio error: could not set info: %s\n",strerror(errno)); goto err; } if(ioctl(fd,AUDIO_GETINFO,&audioinfo)<0) { fprintf(stderr,"Sun audio error: could not get info: %s\n",strerror(errno)); goto err; } if ((audiotype->precision != (uint_t)precision) || (audiotype->channels != (uint_t)channels) || (audiotype->sample_rate != (uint_t)rate) || (audiotype->encoding != (uint_t)afmt)) { fprintf(stderr,"Sun audio error: could not set info properly\n"); goto err; } /* If would not flush, data has MAX input level at 99 */ if(ioctl(fd, I_FLUSH, FLUSHRW)<0) { fprintf(stderr,"Sun audio error: could not flush queues: %s\n",strerror(errno)); goto err; } telmi = new QSocketNotifier(fd, record ? QSocketNotifier::Read : QSocketNotifier::Write); QObject::connect(telmi,SIGNAL(activated(int)), this, SLOT(sounddata(int))); stat = record ? STATUS_RECORD : STATUS_PLAYBACK; p.channels = audiotype->channels; p.rate = audiotype->sample_rate; p.blocksize = audiotype->buffer_size; p.latency = p.blocksize * 1000 / p.channels / p.rate; switch (afmt) { case AUDIO_ENCODING_ULAW: p.format = FMT_8BIT; break; case AUDIO_ENCODING_LINEAR: p.latency /= 2; p.format = FMT_16BIT; break; default: fprintf(stderr,"oops(open): unsupported sound format\n"); exit(1); } emit newparams(&p); rate = p.rate; channels = p.channels; blocksize = p.blocksize; latency = p.latency; DEBUG(printf("%s (format=%d, %s, rate=%d, blocksize=%d, latency=%d ms)\n", record ? "recording" : "playback", afmt, (p.channels == 2) ? "stereo" : "mono", p.rate, p.blocksize, p.latency)); DEBUG(printf("Sound driver opened\n")); return 0; err: if (-1 != fd) close(fd); stat = STATUS_CLOSED; fd = -1; return -1; } void Soundcard::close_dev() { close(fd); fd = -1; stat = STATUS_CLOSED; if (telmi) { delete telmi; telmi = NULL; } DEBUG(printf("Sound driver closed\n")); return; } void Soundcard::setparams(struct SOUNDPARAMS *p) { rate = p->rate; channels = p->channels; switch (p->format) { case FMT_8BIT: afmt = AUDIO_ENCODING_ULAW; break; case FMT_16BIT: afmt = AUDIO_ENCODING_LINEAR; break; default: fprintf(stderr,"oops(set): unsupported sound %d format\n",p->format); exit(1); } switch (stat) { case STATUS_RECORD: close_dev(); open_dev(TRUE); break; case STATUS_PLAYBACK: close_dev(); open_dev(FALSE); break; case STATUS_CLOSED: if (!init_done) get_capabilities(); if (!init_done) return; if (0 == open_dev(TRUE)) close_dev(); break; } } void Soundcard::sounddata(int s) { switch (stat) { case STATUS_RECORD: read(fd,buffer,blocksize); emit senddata((void*)buffer); break; case STATUS_PLAYBACK: emit receivedata((void*)buffer); write(fd,buffer,blocksize); emit senddata((void*)buffer); /* fft :-) */ break; } } #endif