| 1 | /* |
|---|
| 2 | mediastreamer2 library - modular sound and video processing and streaming |
|---|
| 3 | Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) |
|---|
| 4 | |
|---|
| 5 | This program is free software; you can redistribute it and/or |
|---|
| 6 | modify it under the terms of the GNU General Public License |
|---|
| 7 | as published by the Free Software Foundation; either version 2 |
|---|
| 8 | of the License, or (at your option) any later version. |
|---|
| 9 | |
|---|
| 10 | This program is distributed in the hope that it will be useful, |
|---|
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | GNU General Public License for more details. |
|---|
| 14 | |
|---|
| 15 | You should have received a copy of the GNU General Public License |
|---|
| 16 | along with this program; if not, write to the Free Software |
|---|
| 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|---|
| 18 | */ |
|---|
| 19 | |
|---|
| 20 | |
|---|
| 21 | |
|---|
| 22 | #include "mediastreamer2/mssndcard.h" |
|---|
| 23 | #include "mediastreamer2/msfilter.h" |
|---|
| 24 | |
|---|
| 25 | #include <sys/soundcard.h> |
|---|
| 26 | |
|---|
| 27 | #include <errno.h> |
|---|
| 28 | #include <assert.h> |
|---|
| 29 | #include <fcntl.h> |
|---|
| 30 | #include <sys/time.h> |
|---|
| 31 | #include <sys/ioctl.h> |
|---|
| 32 | #include <unistd.h> |
|---|
| 33 | #include <alloca.h> |
|---|
| 34 | |
|---|
| 35 | MSFilter *ms_oss_read_new(MSSndCard *card); |
|---|
| 36 | MSFilter *ms_oss_write_new(MSSndCard *card); |
|---|
| 37 | |
|---|
| 38 | |
|---|
| 39 | static int configure_fd(int fd, int bits,int stereo, int rate, int *minsz) |
|---|
| 40 | { |
|---|
| 41 | int p=0,cond=0; |
|---|
| 42 | int i=0; |
|---|
| 43 | int min_size=0,blocksize=512; |
|---|
| 44 | int err; |
|---|
| 45 | |
|---|
| 46 | //g_message("opening sound device"); |
|---|
| 47 | /* unset nonblocking mode */ |
|---|
| 48 | /* We wanted non blocking open but now put it back to normal ; thanks Xine !*/ |
|---|
| 49 | fcntl(fd, F_SETFL, fcntl(fd, F_GETFL)&~O_NONBLOCK); |
|---|
| 50 | |
|---|
| 51 | /* reset is maybe not needed but takes time*/ |
|---|
| 52 | /*ioctl(fd, SNDCTL_DSP_RESET, 0); */ |
|---|
| 53 | |
|---|
| 54 | p=AFMT_S16_NE; |
|---|
| 55 | |
|---|
| 56 | err=ioctl(fd,SNDCTL_DSP_SETFMT,&p); |
|---|
| 57 | if (err<0){ |
|---|
| 58 | ms_warning("oss_open: can't set sample format:%s.",strerror(errno)); |
|---|
| 59 | } |
|---|
| 60 | |
|---|
| 61 | |
|---|
| 62 | p = bits; /* 16 bits */ |
|---|
| 63 | err=ioctl(fd, SNDCTL_DSP_SAMPLESIZE, &p); |
|---|
| 64 | if (err<0){ |
|---|
| 65 | ms_warning("oss_open: can't set sample size to %i:%s.",bits,strerror(errno)); |
|---|
| 66 | } |
|---|
| 67 | |
|---|
| 68 | p = rate; /* rate in khz*/ |
|---|
| 69 | err=ioctl(fd, SNDCTL_DSP_SPEED, &p); |
|---|
| 70 | if (err<0){ |
|---|
| 71 | ms_warning("oss_open: can't set sample rate to %i:%s.",rate,strerror(errno)); |
|---|
| 72 | } |
|---|
| 73 | |
|---|
| 74 | p = stereo; /* stereo or not */ |
|---|
| 75 | err=ioctl(fd, SNDCTL_DSP_STEREO, &p); |
|---|
| 76 | if (err<0){ |
|---|
| 77 | ms_warning("oss_open: can't set mono/stereo mode:%s.",strerror(errno)); |
|---|
| 78 | } |
|---|
| 79 | |
|---|
| 80 | if (rate==16000) blocksize=4096; /* oss emulation is not very good at 16khz */ |
|---|
| 81 | else blocksize=blocksize*(rate/8000); |
|---|
| 82 | |
|---|
| 83 | ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size); |
|---|
| 84 | |
|---|
| 85 | /** |
|---|
| 86 | * first try SNDCTL_DSP_SETFRAGMENT |
|---|
| 87 | */ |
|---|
| 88 | if (min_size>blocksize) { |
|---|
| 89 | int size_selector=0; |
|---|
| 90 | while ((blocksize >> size_selector) != 1)size_selector++; /*compute selector blocksize = 1<< size_selector*/ |
|---|
| 91 | int frag = (2 << 16) | (size_selector); |
|---|
| 92 | if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag) == -1) { |
|---|
| 93 | ms_warning("This OSS driver does not support trying subdivise",SNDCTL_DSP_SETFRAGMENT); |
|---|
| 94 | ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size); |
|---|
| 95 | |
|---|
| 96 | /* try to subdivide BLKSIZE to reach block size if necessary */ |
|---|
| 97 | if (min_size>blocksize) |
|---|
| 98 | { |
|---|
| 99 | cond=1; |
|---|
| 100 | p=min_size/blocksize; |
|---|
| 101 | while(cond) |
|---|
| 102 | { |
|---|
| 103 | i=ioctl(fd, SNDCTL_DSP_SUBDIVIDE, &p); |
|---|
| 104 | ms_message("subdivide bloc min_size [%i] block_size [%i] said error=%i,errno=%i\n",min_size,blocksize,i,errno); |
|---|
| 105 | if ((i!=0) || (p==1)) cond=0; |
|---|
| 106 | else p=p/2; |
|---|
| 107 | } |
|---|
| 108 | } |
|---|
| 109 | ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size); |
|---|
| 110 | } else { |
|---|
| 111 | /*it's working*/ |
|---|
| 112 | min_size=1 << (frag&0x0FFFF); |
|---|
| 113 | ms_message("Max fragment=%x, size selector=%x block size=%i",frag>>16,frag&0x0FFFF,min_size); |
|---|
| 114 | } |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | if (min_size>blocksize) |
|---|
| 118 | { |
|---|
| 119 | ms_warning("dsp block size set to %i.",min_size); |
|---|
| 120 | }else{ |
|---|
| 121 | /* no need to access the card with less latency than needed*/ |
|---|
| 122 | min_size=blocksize; |
|---|
| 123 | } |
|---|
| 124 | |
|---|
| 125 | ms_message("/dev/dsp opened: rate=%i,bits=%i,stereo=%i blocksize=%i.", |
|---|
| 126 | rate,bits,stereo,min_size); |
|---|
| 127 | |
|---|
| 128 | /* start recording !!! Alex */ |
|---|
| 129 | { |
|---|
| 130 | int fl,res; |
|---|
| 131 | |
|---|
| 132 | fl=PCM_ENABLE_OUTPUT|PCM_ENABLE_INPUT; |
|---|
| 133 | res=ioctl(fd, SNDCTL_DSP_SETTRIGGER, &fl); |
|---|
| 134 | if (res<0) ms_warning("OSS_TRIGGER: %s",strerror(errno)); |
|---|
| 135 | } |
|---|
| 136 | *minsz=min_size; |
|---|
| 137 | return fd; |
|---|
| 138 | } |
|---|
| 139 | |
|---|
| 140 | |
|---|
| 141 | typedef struct OssData{ |
|---|
| 142 | char *pcmdev; |
|---|
| 143 | char *mixdev; |
|---|
| 144 | int pcmfd_read; |
|---|
| 145 | int pcmfd_write; |
|---|
| 146 | int rate; |
|---|
| 147 | int bits; |
|---|
| 148 | ms_thread_t thread; |
|---|
| 149 | ms_mutex_t mutex; |
|---|
| 150 | queue_t rq; |
|---|
| 151 | MSBufferizer * bufferizer; |
|---|
| 152 | bool_t read_started; |
|---|
| 153 | bool_t write_started; |
|---|
| 154 | bool_t stereo; |
|---|
| 155 | } OssData; |
|---|
| 156 | |
|---|
| 157 | static void oss_open(OssData* d, int *minsz){ |
|---|
| 158 | int fd=open(d->pcmdev,O_RDWR|O_NONBLOCK); |
|---|
| 159 | if (fd>0) { |
|---|
| 160 | d->pcmfd_read=d->pcmfd_write=configure_fd(fd, d->bits, d->stereo, d->rate, minsz); |
|---|
| 161 | return ; |
|---|
| 162 | } |
|---|
| 163 | ms_warning ("Cannot open a single fd in rw mode for [%s] trying to open two",d->pcmdev); |
|---|
| 164 | |
|---|
| 165 | d->pcmfd_read=open(d->pcmdev,O_RDONLY|O_NONBLOCK); |
|---|
| 166 | if (d->pcmfd_read > 0) { |
|---|
| 167 | d->pcmfd_read=configure_fd(d->pcmfd_read, d->bits, d->stereo, d->rate, minsz); |
|---|
| 168 | } else { |
|---|
| 169 | ms_error("Cannot open fd in ro mode for [%s]",d->pcmdev); |
|---|
| 170 | } |
|---|
| 171 | d->pcmfd_write=open(d->pcmdev,O_WRONLY|O_NONBLOCK); |
|---|
| 172 | if (d->pcmfd_write > 0) { |
|---|
| 173 | d->pcmfd_write=configure_fd(d->pcmfd_write, d->bits, d->stereo, d->rate, minsz); |
|---|
| 174 | } else { |
|---|
| 175 | ms_error("Cannot open fd in wr mode for [%s]",d->pcmdev); |
|---|
| 176 | } |
|---|
| 177 | return ; |
|---|
| 178 | } |
|---|
| 179 | |
|---|
| 180 | static void oss_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent) |
|---|
| 181 | { |
|---|
| 182 | OssData *d=(OssData*)card->data; |
|---|
| 183 | int p,mix_fd; |
|---|
| 184 | int osscmd; |
|---|
| 185 | if (d->mixdev==NULL) return; |
|---|
| 186 | switch(e){ |
|---|
| 187 | case MS_SND_CARD_MASTER: |
|---|
| 188 | osscmd=SOUND_MIXER_VOLUME; |
|---|
| 189 | break; |
|---|
| 190 | case MS_SND_CARD_CAPTURE: |
|---|
| 191 | osscmd=SOUND_MIXER_IGAIN; |
|---|
| 192 | break; |
|---|
| 193 | case MS_SND_CARD_PLAYBACK: |
|---|
| 194 | osscmd=SOUND_MIXER_PCM; |
|---|
| 195 | break; |
|---|
| 196 | default: |
|---|
| 197 | ms_warning("oss_card_set_level: unsupported command."); |
|---|
| 198 | return; |
|---|
| 199 | } |
|---|
| 200 | p=(((int)percent)<<8 | (int)percent); |
|---|
| 201 | mix_fd = open(d->mixdev, O_WRONLY); |
|---|
| 202 | ioctl(mix_fd,MIXER_WRITE(osscmd), &p); |
|---|
| 203 | close(mix_fd); |
|---|
| 204 | } |
|---|
| 205 | |
|---|
| 206 | static int oss_get_level(MSSndCard *card, MSSndCardMixerElem e) |
|---|
| 207 | { |
|---|
| 208 | OssData *d=(OssData*)card->data; |
|---|
| 209 | int p=0,mix_fd; |
|---|
| 210 | int osscmd; |
|---|
| 211 | if (d->mixdev==NULL) return -1; |
|---|
| 212 | switch(e){ |
|---|
| 213 | case MS_SND_CARD_MASTER: |
|---|
| 214 | osscmd=SOUND_MIXER_VOLUME; |
|---|
| 215 | break; |
|---|
| 216 | case MS_SND_CARD_CAPTURE: |
|---|
| 217 | osscmd=SOUND_MIXER_IGAIN; |
|---|
| 218 | break; |
|---|
| 219 | case MS_SND_CARD_PLAYBACK: |
|---|
| 220 | osscmd=SOUND_MIXER_PCM; |
|---|
| 221 | break; |
|---|
| 222 | default: |
|---|
| 223 | ms_warning("oss_card_get_level: unsupported command."); |
|---|
| 224 | return -1; |
|---|
| 225 | } |
|---|
| 226 | mix_fd = open(d->mixdev, O_RDONLY); |
|---|
| 227 | ioctl(mix_fd,MIXER_READ(osscmd), &p); |
|---|
| 228 | close(mix_fd); |
|---|
| 229 | return p>>8; |
|---|
| 230 | } |
|---|
| 231 | |
|---|
| 232 | static void oss_set_source(MSSndCard *card, MSSndCardCapture source) |
|---|
| 233 | { |
|---|
| 234 | OssData *d=(OssData*)card->data; |
|---|
| 235 | int p=0; |
|---|
| 236 | int mix_fd; |
|---|
| 237 | if (d->mixdev==NULL) return; |
|---|
| 238 | |
|---|
| 239 | switch(source){ |
|---|
| 240 | case MS_SND_CARD_MIC: |
|---|
| 241 | p = 1 << SOUND_MIXER_MIC; |
|---|
| 242 | break; |
|---|
| 243 | case MS_SND_CARD_LINE: |
|---|
| 244 | p = 1 << SOUND_MIXER_LINE; |
|---|
| 245 | break; |
|---|
| 246 | } |
|---|
| 247 | |
|---|
| 248 | mix_fd = open(d->mixdev, O_WRONLY); |
|---|
| 249 | ioctl(mix_fd, SOUND_MIXER_WRITE_RECSRC, &p); |
|---|
| 250 | close(mix_fd); |
|---|
| 251 | } |
|---|
| 252 | |
|---|
| 253 | static void oss_init(MSSndCard *card){ |
|---|
| 254 | OssData *d=ms_new(OssData,1); |
|---|
| 255 | d->pcmdev=NULL; |
|---|
| 256 | d->mixdev=NULL; |
|---|
| 257 | d->pcmfd_read=-1; |
|---|
| 258 | d->pcmfd_write=-1; |
|---|
| 259 | d->read_started=FALSE; |
|---|
| 260 | d->write_started=FALSE; |
|---|
| 261 | d->bits=16; |
|---|
| 262 | d->rate=8000; |
|---|
| 263 | d->stereo=FALSE; |
|---|
| 264 | qinit(&d->rq); |
|---|
| 265 | d->bufferizer=ms_bufferizer_new(); |
|---|
| 266 | ms_mutex_init(&d->mutex,NULL); |
|---|
| 267 | card->data=d; |
|---|
| 268 | } |
|---|
| 269 | |
|---|
| 270 | static void oss_uninit(MSSndCard *card){ |
|---|
| 271 | OssData *d=(OssData*)card->data; |
|---|
| 272 | if (d->pcmdev!=NULL) ms_free(d->pcmdev); |
|---|
| 273 | if (d->mixdev!=NULL) ms_free(d->mixdev); |
|---|
| 274 | ms_bufferizer_destroy(d->bufferizer); |
|---|
| 275 | flushq(&d->rq,0); |
|---|
| 276 | ms_mutex_destroy(&d->mutex); |
|---|
| 277 | ms_free(d); |
|---|
| 278 | } |
|---|
| 279 | |
|---|
| 280 | #define DSP_NAME "/dev/dsp" |
|---|
| 281 | #define MIXER_NAME "/dev/mixer" |
|---|
| 282 | |
|---|
| 283 | static void oss_detect(MSSndCardManager *m); |
|---|
| 284 | |
|---|
| 285 | MSSndCardDesc oss_card_desc={ |
|---|
| 286 | .driver_type="OSS", |
|---|
| 287 | .detect=oss_detect, |
|---|
| 288 | .init=oss_init, |
|---|
| 289 | .set_level=oss_set_level, |
|---|
| 290 | .get_level=oss_get_level, |
|---|
| 291 | .set_capture=oss_set_source, |
|---|
| 292 | .create_reader=ms_oss_read_new, |
|---|
| 293 | .create_writer=ms_oss_write_new, |
|---|
| 294 | .uninit=oss_uninit |
|---|
| 295 | }; |
|---|
| 296 | |
|---|
| 297 | static MSSndCard *oss_card_new(const char *pcmdev, const char *mixdev){ |
|---|
| 298 | MSSndCard *card=ms_snd_card_new(&oss_card_desc); |
|---|
| 299 | OssData *d=(OssData*)card->data; |
|---|
| 300 | d->pcmdev=ms_strdup(pcmdev); |
|---|
| 301 | d->mixdev=ms_strdup(mixdev); |
|---|
| 302 | card->name=ms_strdup(pcmdev); |
|---|
| 303 | return card; |
|---|
| 304 | } |
|---|
| 305 | |
|---|
| 306 | static void oss_detect(MSSndCardManager *m){ |
|---|
| 307 | int i; |
|---|
| 308 | char pcmdev[sizeof(DSP_NAME)+3]; |
|---|
| 309 | char mixdev[sizeof(MIXER_NAME)+3]; |
|---|
| 310 | if (access(DSP_NAME,F_OK)==0){ |
|---|
| 311 | MSSndCard *card=oss_card_new(DSP_NAME,MIXER_NAME); |
|---|
| 312 | ms_snd_card_manager_add_card(m,card); |
|---|
| 313 | } |
|---|
| 314 | for(i=0;i<10;i++){ |
|---|
| 315 | snprintf(pcmdev,sizeof(pcmdev),"%s%i",DSP_NAME,i); |
|---|
| 316 | snprintf(mixdev,sizeof(mixdev),"%s%i",MIXER_NAME,i); |
|---|
| 317 | if (access(pcmdev,F_OK)==0){ |
|---|
| 318 | MSSndCard *card=oss_card_new(pcmdev,mixdev); |
|---|
| 319 | ms_snd_card_manager_add_card(m,card); |
|---|
| 320 | } |
|---|
| 321 | } |
|---|
| 322 | } |
|---|
| 323 | |
|---|
| 324 | static void * oss_thread(void *p){ |
|---|
| 325 | MSSndCard *card=(MSSndCard*)p; |
|---|
| 326 | OssData *d=(OssData*)card->data; |
|---|
| 327 | int bsize=0; |
|---|
| 328 | uint8_t *rtmpbuff=NULL; |
|---|
| 329 | uint8_t *wtmpbuff=NULL; |
|---|
| 330 | int err; |
|---|
| 331 | mblk_t *rm=NULL; |
|---|
| 332 | oss_open(d,&bsize); |
|---|
| 333 | if (d->pcmfd_read>=0){ |
|---|
| 334 | rtmpbuff=(uint8_t*)alloca(bsize); |
|---|
| 335 | } |
|---|
| 336 | if (d->pcmfd_write>=0){ |
|---|
| 337 | wtmpbuff=(uint8_t*)alloca(bsize); |
|---|
| 338 | } |
|---|
| 339 | while(d->read_started || d->write_started){ |
|---|
| 340 | if (d->pcmfd_read>=0){ |
|---|
| 341 | if (d->read_started){ |
|---|
| 342 | if (rm==NULL) rm=allocb(bsize,0); |
|---|
| 343 | err=read(d->pcmfd_read,rm->b_wptr,bsize); |
|---|
| 344 | if (err<0){ |
|---|
| 345 | ms_warning("Fail to read %i bytes from soundcard: %s", |
|---|
| 346 | bsize,strerror(errno)); |
|---|
| 347 | }else{ |
|---|
| 348 | rm->b_wptr+=err; |
|---|
| 349 | putq(&d->rq,rm); |
|---|
| 350 | rm=NULL; |
|---|
| 351 | } |
|---|
| 352 | }else { |
|---|
| 353 | int sz = read(d->pcmfd_read,rtmpbuff,bsize); |
|---|
| 354 | if( sz!=bsize) ms_warning("sound device read returned %i !",sz); |
|---|
| 355 | } |
|---|
| 356 | if (d->write_started){ |
|---|
| 357 | err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize); |
|---|
| 358 | if (err==bsize){ |
|---|
| 359 | err=write(d->pcmfd_write,wtmpbuff,bsize); |
|---|
| 360 | if (err<0){ |
|---|
| 361 | ms_warning("Fail to write %i bytes from soundcard: %s", |
|---|
| 362 | bsize,strerror(errno)); |
|---|
| 363 | } |
|---|
| 364 | } |
|---|
| 365 | }else { |
|---|
| 366 | int sz; |
|---|
| 367 | memset(wtmpbuff,0,bsize); |
|---|
| 368 | sz = write(d->pcmfd_write,wtmpbuff,bsize); |
|---|
| 369 | if( sz!=bsize) ms_warning("sound device write returned %i !",sz); |
|---|
| 370 | } |
|---|
| 371 | }else usleep(20000); |
|---|
| 372 | } |
|---|
| 373 | if (d->pcmfd_read==d->pcmfd_write && d->pcmfd_read>=0 ) { |
|---|
| 374 | close(d->pcmfd_read); |
|---|
| 375 | d->pcmfd_read = d->pcmfd_write =-1; |
|---|
| 376 | } else { |
|---|
| 377 | if (d->pcmfd_read>=0) { |
|---|
| 378 | close(d->pcmfd_read); |
|---|
| 379 | d->pcmfd_read=-1; |
|---|
| 380 | } |
|---|
| 381 | if (d->pcmfd_write>=0) { |
|---|
| 382 | close(d->pcmfd_write); |
|---|
| 383 | d->pcmfd_write=-1; |
|---|
| 384 | } |
|---|
| 385 | } |
|---|
| 386 | |
|---|
| 387 | return NULL; |
|---|
| 388 | } |
|---|
| 389 | |
|---|
| 390 | static void oss_start_r(MSSndCard *card){ |
|---|
| 391 | OssData *d=(OssData*)card->data; |
|---|
| 392 | if (d->read_started==FALSE && d->write_started==FALSE){ |
|---|
| 393 | d->read_started=TRUE; |
|---|
| 394 | ms_thread_create(&d->thread,NULL,oss_thread,card); |
|---|
| 395 | }else d->read_started=TRUE; |
|---|
| 396 | } |
|---|
| 397 | |
|---|
| 398 | static void oss_stop_r(MSSndCard *card){ |
|---|
| 399 | OssData *d=(OssData*)card->data; |
|---|
| 400 | d->read_started=FALSE; |
|---|
| 401 | if (d->write_started==FALSE){ |
|---|
| 402 | ms_thread_join(d->thread,NULL); |
|---|
| 403 | } |
|---|
| 404 | } |
|---|
| 405 | |
|---|
| 406 | static void oss_start_w(MSSndCard *card){ |
|---|
| 407 | OssData *d=(OssData*)card->data; |
|---|
| 408 | if (d->read_started==FALSE && d->write_started==FALSE){ |
|---|
| 409 | d->write_started=TRUE; |
|---|
| 410 | ms_thread_create(&d->thread,NULL,oss_thread,card); |
|---|
| 411 | }else{ |
|---|
| 412 | d->write_started=TRUE; |
|---|
| 413 | } |
|---|
| 414 | } |
|---|
| 415 | |
|---|
| 416 | static void oss_stop_w(MSSndCard *card){ |
|---|
| 417 | OssData *d=(OssData*)card->data; |
|---|
| 418 | d->write_started=FALSE; |
|---|
| 419 | if (d->read_started==FALSE){ |
|---|
| 420 | ms_thread_join(d->thread,NULL); |
|---|
| 421 | } |
|---|
| 422 | } |
|---|
| 423 | |
|---|
| 424 | static mblk_t *oss_get(MSSndCard *card){ |
|---|
| 425 | OssData *d=(OssData*)card->data; |
|---|
| 426 | mblk_t *m; |
|---|
| 427 | ms_mutex_lock(&d->mutex); |
|---|
| 428 | m=getq(&d->rq); |
|---|
| 429 | ms_mutex_unlock(&d->mutex); |
|---|
| 430 | return m; |
|---|
| 431 | } |
|---|
| 432 | |
|---|
| 433 | static void oss_put(MSSndCard *card, mblk_t *m){ |
|---|
| 434 | OssData *d=(OssData*)card->data; |
|---|
| 435 | ms_mutex_lock(&d->mutex); |
|---|
| 436 | ms_bufferizer_put(d->bufferizer,m); |
|---|
| 437 | ms_mutex_unlock(&d->mutex); |
|---|
| 438 | } |
|---|
| 439 | |
|---|
| 440 | |
|---|
| 441 | static void oss_read_preprocess(MSFilter *f){ |
|---|
| 442 | MSSndCard *card=(MSSndCard*)f->data; |
|---|
| 443 | oss_start_r(card); |
|---|
| 444 | } |
|---|
| 445 | |
|---|
| 446 | static void oss_read_postprocess(MSFilter *f){ |
|---|
| 447 | MSSndCard *card=(MSSndCard*)f->data; |
|---|
| 448 | oss_stop_r(card); |
|---|
| 449 | } |
|---|
| 450 | |
|---|
| 451 | static void oss_read_process(MSFilter *f){ |
|---|
| 452 | MSSndCard *card=(MSSndCard*)f->data; |
|---|
| 453 | mblk_t *m; |
|---|
| 454 | while((m=oss_get(card))!=NULL){ |
|---|
| 455 | ms_queue_put(f->outputs[0],m); |
|---|
| 456 | } |
|---|
| 457 | } |
|---|
| 458 | |
|---|
| 459 | static void oss_write_preprocess(MSFilter *f){ |
|---|
| 460 | MSSndCard *card=(MSSndCard*)f->data; |
|---|
| 461 | oss_start_w(card); |
|---|
| 462 | } |
|---|
| 463 | |
|---|
| 464 | static void oss_write_postprocess(MSFilter *f){ |
|---|
| 465 | MSSndCard *card=(MSSndCard*)f->data; |
|---|
| 466 | oss_stop_w(card); |
|---|
| 467 | } |
|---|
| 468 | |
|---|
| 469 | static void oss_write_process(MSFilter *f){ |
|---|
| 470 | MSSndCard *card=(MSSndCard*)f->data; |
|---|
| 471 | mblk_t *m; |
|---|
| 472 | while((m=ms_queue_get(f->inputs[0]))!=NULL){ |
|---|
| 473 | oss_put(card,m); |
|---|
| 474 | } |
|---|
| 475 | } |
|---|
| 476 | |
|---|
| 477 | static int set_rate(MSFilter *f, void *arg){ |
|---|
| 478 | MSSndCard *card=(MSSndCard*)f->data; |
|---|
| 479 | OssData *d=(OssData*)card->data; |
|---|
| 480 | d->rate=*((int*)arg); |
|---|
| 481 | return 0; |
|---|
| 482 | } |
|---|
| 483 | |
|---|
| 484 | static int set_nchannels(MSFilter *f, void *arg){ |
|---|
| 485 | MSSndCard *card=(MSSndCard*)f->data; |
|---|
| 486 | OssData *d=(OssData*)card->data; |
|---|
| 487 | d->stereo=(*((int*)arg)==2); |
|---|
| 488 | return 0; |
|---|
| 489 | } |
|---|
| 490 | |
|---|
| 491 | static MSFilterMethod oss_methods[]={ |
|---|
| 492 | { MS_FILTER_SET_SAMPLE_RATE , set_rate }, |
|---|
| 493 | { MS_FILTER_SET_NCHANNELS , set_nchannels }, |
|---|
| 494 | { 0 , NULL } |
|---|
| 495 | }; |
|---|
| 496 | |
|---|
| 497 | MSFilterDesc oss_read_desc={ |
|---|
| 498 | .id=MS_OSS_READ_ID, |
|---|
| 499 | .name="MSOssRead", |
|---|
| 500 | .text="Sound capture filter for OSS drivers", |
|---|
| 501 | .category=MS_FILTER_OTHER, |
|---|
| 502 | .ninputs=0, |
|---|
| 503 | .noutputs=1, |
|---|
| 504 | .preprocess=oss_read_preprocess, |
|---|
| 505 | .process=oss_read_process, |
|---|
| 506 | .postprocess=oss_read_postprocess, |
|---|
| 507 | .methods=oss_methods |
|---|
| 508 | }; |
|---|
| 509 | |
|---|
| 510 | |
|---|
| 511 | MSFilterDesc oss_write_desc={ |
|---|
| 512 | .id=MS_OSS_WRITE_ID, |
|---|
| 513 | .name="MSOssWrite", |
|---|
| 514 | .text="Sound playback filter for OSS drivers", |
|---|
| 515 | .category=MS_FILTER_OTHER, |
|---|
| 516 | .ninputs=1, |
|---|
| 517 | .noutputs=0, |
|---|
| 518 | .preprocess=oss_write_preprocess, |
|---|
| 519 | .process=oss_write_process, |
|---|
| 520 | .postprocess=oss_write_postprocess, |
|---|
| 521 | .methods=oss_methods |
|---|
| 522 | }; |
|---|
| 523 | |
|---|
| 524 | MSFilter *ms_oss_read_new(MSSndCard *card){ |
|---|
| 525 | MSFilter *f=ms_filter_new_from_desc(&oss_read_desc); |
|---|
| 526 | f->data=card; |
|---|
| 527 | return f; |
|---|
| 528 | } |
|---|
| 529 | |
|---|
| 530 | |
|---|
| 531 | MSFilter *ms_oss_write_new(MSSndCard *card){ |
|---|
| 532 | MSFilter *f=ms_filter_new_from_desc(&oss_write_desc); |
|---|
| 533 | f->data=card; |
|---|
| 534 | return f; |
|---|
| 535 | } |
|---|
| 536 | |
|---|
| 537 | MS_FILTER_DESC_EXPORT(oss_read_desc) |
|---|
| 538 | MS_FILTER_DESC_EXPORT(oss_write_desc) |
|---|