aboutsummaryrefslogtreecommitdiffstats
path: root/sunaudio.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sunaudio.cpp')
-rw-r--r--sunaudio.cpp369
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
+