diff options
Diffstat (limited to 'sunaudio.cpp')
-rw-r--r-- | sunaudio.cpp | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/sunaudio.cpp b/sunaudio.cpp new file mode 100644 index 0000000..d1c3b97 --- /dev/null +++ b/sunaudio.cpp @@ -0,0 +1,369 @@ +#ifdef HAVE_SUN_AUDIOIO_H + +/* + * Soundcard class for Solaris + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/ioctl.h> +#include <sys/audioio.h> + +/* for ioctl(I_FLUSH) */ +#include <stropts.h> +#include <sys/conf.h> + +#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 + |