📄 oss.cpp
字号:
#if defined(HAVE_SOUNDCARD_H) || defined(HAVE_SYS_SOUNDCARD_H)#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <fcntl.h>#include <errno.h>#include <sys/ioctl.h>#ifdef HAVE_SOUNDCARD_H# include <soundcard.h>#endif#ifdef HAVE_SYS_SOUNDCARD_H# include <sys/soundcard.h>#endif#include "sound.h"#include "oss.moc"#ifndef OSS_GETVERSION#define OSS_GETVERSION _IOR('M',118,int)#endif/* ---------------------------------------------------------------------- */Soundcard::Soundcard(const char *dev){ if (dev) strcpy(devname,dev); else strcpy(devname,"/dev/dsp"); driver_name[0] = '\0'; stat = STATUS_CLOSED; get_capabilities(); channels = 1; rate = 22050; fd = -1;}Soundcard::~Soundcard(){ /* nothing */}intSoundcard::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;}intSoundcard::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;}intSoundcard::kill_buffer(){ ioctl(fd,SNDCTL_DSP_RESET,0); return 0;}intSoundcard::stop(){ if (stat != STATUS_CLOSED) close_dev(); return 0;}/* ---------------------------------------------------------------------- */voidSoundcard::get_capabilities(){ int i,dsp; int try_afmt; int try_channels; afmt = 0; if (-1 != (dsp = open(devname, O_RDONLY))) { ioctl(dsp, SNDCTL_DSP_SETFMT, &afmt); /* current */ ioctl(dsp, SNDCTL_DSP_GETFMTS, &afmt_hw); /* hardware cap */ afmt_sw = 0; for (i = 0; i < 16 /* XXX */; i++) { try_afmt = (1<<i); if (-1 == ioctl(dsp, SNDCTL_DSP_SETFMT, &try_afmt)) continue; if (try_afmt != (1<<i)) continue; afmt_sw |= try_afmt; } try_channels = 2; if (-1 != ioctl(dsp, SNDCTL_DSP_CHANNELS, &try_channels) && 2 == try_channels) channels_hw = 2; else channels_hw = 1; /* version check */ if (-1 == ioctl(dsp,OSS_GETVERSION,&i)) { strcpy(driver_name,"OSS (version unknown)"); } else { sprintf(driver_name,"OSS %d.%d.%d%c", (i>>16) & 0xff,(i>>8) & 0xff,(i>>4) & 0xf,(i&0xf)+'a'); } close(dsp); init_done = 1; } else { init_done = 0; }}intSoundcard::has_channels(){ if (!init_done) return -1; return channels_hw;}intSoundcard::has_format(int f){ if (!init_done) return -1; switch (f) { case FMT_8BIT: return (afmt_hw & AFMT_U8) ? 1 : 0; break; case FMT_16BIT: return (afmt_hw & AFMT_S16_LE) ? 1 : 0; break; case FMT_MULAW: case FMT_ALAW: default: return 0; }}char*Soundcard::driver(){ return driver_name;}intSoundcard::open_dev(int record){ struct SOUNDPARAMS p; int frag,rrate; if (-1 == (fd = open(devname,record ? O_RDONLY : O_WRONLY))) goto err; fcntl(fd,F_SETFD,FD_CLOEXEC); /* try to get ~50 ms latency */ blocksize = 50*channels*rate/1000; if (afmt == AFMT_U16_BE || afmt == AFMT_S16_BE || afmt == AFMT_U16_LE || afmt == AFMT_S16_LE) blocksize *= 2; for (frag = 0; blocksize != 1; frag++) blocksize >>= 1;#if 0 fprintf(stderr,"asking for %d byte blocksize\n",1 << frag);#endif frag |= 0x7fff0000; if (-1 == ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag)) perror("ioctl SNDCTL_DSP_SETFRAGMENT"); rrate = rate; if (-1 == ioctl(fd, SNDCTL_DSP_SETFMT, &afmt)) { perror("ioctl SNDCTL_DSP_SETFMT"); goto err; } if (-1 == ioctl(fd, SNDCTL_DSP_CHANNELS, &channels)) { perror("ioctl SNDCTL_DSP_SETFMT"); goto err; } if (-1 == ioctl(fd, SNDCTL_DSP_SPEED, &rrate)) { perror("ioctl SNDCTL_DSP_SETFMT"); goto err; } if (-1 == ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &blocksize)) { perror("ioctl SNDCTL_DSP_SETFMT"); goto err; } if (0 == blocksize) blocksize = 4096; if (rrate != rate) { fprintf(stderr,"sample rate: asked for %d, hardware uses %d. ", rate,rrate); if (abs(rate-rrate)*100 < rate) { fprintf(stderr,"that's fine (diff <1%%).\n"); } else { fprintf(stderr,"way off, using hardware rate.\n"); rate = rrate; } } latency = blocksize*1000/channels/rate; if (afmt == AFMT_U16_BE || afmt == AFMT_S16_BE || afmt == AFMT_U16_LE || afmt == AFMT_S16_LE) latency = latency/2; 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;#if 0 fprintf(stderr,"%s (format=%d, %s, rate=%d, blocksize=%d, latency=%d ms)\n", record ? "recording" : "playback", afmt, (channels == 2) ? "stereo" : "mono", rate, blocksize, latency);#endif p.channels = channels; p.rate = rate; p.blocksize = blocksize; p.latency = latency; switch (afmt) { case AFMT_U8: p.format = FMT_8BIT; break; case AFMT_S16_LE: p.format = FMT_16BIT; break; default: fprintf(stderr,"oops(open): unsupported sound format\n"); exit(1); } emit newparams(&p); if (record) { trigger = ~PCM_ENABLE_INPUT; ioctl(fd,SNDCTL_DSP_SETTRIGGER,&trigger); trigger = PCM_ENABLE_INPUT; ioctl(fd,SNDCTL_DSP_SETTRIGGER,&trigger); } return 0;err: if (-1 != fd) close(fd); stat = STATUS_CLOSED; fd = -1; return -1;}voidSoundcard::close_dev(){ close(fd); fd = -1; stat = STATUS_CLOSED; delete telmi; return;}voidSoundcard::setparams(struct SOUNDPARAMS *p){ rate = p->rate; channels = p->channels; switch (p->format) { case FMT_8BIT: afmt = AFMT_U8; break; case FMT_16BIT: afmt = AFMT_S16_LE; break; default: fprintf(stderr,"oops(set): unsupported sound format\n"); 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; }}voidSoundcard::sounddata(int s){ int rc,have; switch (stat) { case STATUS_RECORD: /* read */ for (have = 0; have < blocksize;) { rc = read(fd,buffer+have,blocksize-have); switch (rc) { case -1: if (EINTR != errno) { perror("read sound"); exit(1); } break; case 0: fprintf(stderr,"Huh? got 0 bytes from sound device?\n"); exit(1); default: have += rc; } } emit senddata((void*)buffer); break; case STATUS_PLAYBACK: emit receivedata((void*)buffer); if (-1 != fd) write(fd,buffer,blocksize); emit senddata((void*)buffer); /* fft :-) */ break; }}#endif /* SOUNDCARD_H */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -