2 mediastreamer2 library - modular sound and video processing and streaming
3 Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org)
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.
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.
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.
22 #include <alsa/asoundlib.h>
25 #include "mediastreamer2/msfilter.h"
26 #include "mediastreamer2/mssndcard.h"
28 //#define THREADED_VERSION
30 /*in case of troubles with a particular driver, try incrementing ALSA_PERIOD_SIZE
31 to 512, 1024, 2048, 4096...
32 then try incrementing the number of periods*/
33 #define ALSA_PERIODS 8
34 #define ALSA_PERIOD_SIZE 256
36 /*uncomment the following line if you have problems with an alsa driver
37 having sound quality trouble:*/
38 /*#define EPIPE_BUGFIX 1*/
40 static MSSndCard * alsa_card_new(int id);
41 static MSSndCard *alsa_card_duplicate(MSSndCard *obj);
42 static MSFilter * ms_alsa_read_new(const char *dev);
43 static MSFilter * ms_alsa_write_new(const char *dev);
51 typedef struct _AlsaData AlsaData;
54 static int alsa_set_params(snd_pcm_t *pcm_handle, int rw, int bits, int stereo, int rate)
56 snd_pcm_hw_params_t *hwparams=NULL;
57 snd_pcm_sw_params_t *swparams=NULL;
60 unsigned long exact_ulvalue;
62 int periods=ALSA_PERIODS;
63 int periodsize=ALSA_PERIOD_SIZE;
67 /* Allocate the snd_pcm_hw_params_t structure on the stack. */
68 snd_pcm_hw_params_alloca(&hwparams);
70 /* Init hwparams with full configuration space */
71 if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
72 ms_warning("alsa_set_params: Cannot configure this PCM device.");
76 if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
77 ms_warning("alsa_set_params: Error setting access.");
80 /* Set sample format */
81 format=SND_PCM_FORMAT_S16;
82 if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, format) < 0) {
83 ms_warning("alsa_set_params: Error setting format.");
86 /* Set number of channels */
87 if (stereo) channels=2;
89 if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, channels) < 0) {
90 ms_warning("alsa_set_params: Error setting channels.");
93 /* Set sample rate. If the exact rate is not supported */
94 /* by the hardware, use nearest possible rate. */
97 if ((err=snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_uvalue, &dir))<0){
98 ms_warning("alsa_set_params: Error setting rate to %i:%s",rate,snd_strerror(err));
102 ms_warning("alsa_set_params: The rate %d Hz is not supported by your hardware.\n "
103 "==> Using %d Hz instead.", rate, exact_uvalue);
105 /* choose greater period size when rate is high */
106 periodsize=periodsize*(rate/8000);
108 /* Set buffer size (in frames). The resulting latency is given by */
109 /* latency = periodsize * periods / (rate * bytes_per_frame) */
110 /* set period size */
111 exact_ulvalue=periodsize;
113 if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &exact_ulvalue, &dir) < 0) {
114 ms_warning("alsa_set_params: Error setting period size.");
118 ms_warning("alsa_set_params: The period size %d is not supported by your hardware.\n "
119 "==> Using %d instead.", periodsize, (int)exact_ulvalue);
121 ms_warning("alsa_set_params: periodsize:%d Using %d", periodsize, (int)exact_ulvalue);
122 periodsize=exact_ulvalue;
123 /* Set number of periods. Periods used to be called fragments. */
124 exact_uvalue=periods;
126 if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &exact_uvalue, &dir) < 0) {
127 ms_warning("alsa_set_params: Error setting periods.");
130 ms_warning("alsa_set_params: period:%d Using %d", periods, exact_uvalue);
132 ms_warning("alsa_set_params: The number of periods %d is not supported by your hardware.\n "
133 "==> Using %d instead.", periods, exact_uvalue);
135 /* Apply HW parameter settings to */
136 /* PCM device and prepare device */
137 if ((err=snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
138 ms_warning("alsa_set_params: Error setting HW params:%s",snd_strerror(err));
141 /*prepare sw params */
143 snd_pcm_sw_params_alloca(&swparams);
144 snd_pcm_sw_params_current(pcm_handle, swparams);
145 if ((err=snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams,periodsize*2 ))<0){
146 ms_warning("alsa_set_params: Error setting start threshold:%s",snd_strerror(err));
148 if ((err=snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams,periodsize*periods ))<0){
149 ms_warning("alsa_set_params: Error setting stop threshold:%s",snd_strerror(err));
151 if ((err=snd_pcm_sw_params(pcm_handle, swparams))<0){
152 ms_warning("alsa_set_params: Error setting SW params:%s",snd_strerror(err));
160 static void alsa_fill_w (snd_pcm_t *pcm_handle)
162 snd_pcm_hw_params_t *hwparams=NULL;
164 snd_pcm_uframes_t buffer_size;
165 int buffer_size_bytes;
168 /* Allocate the snd_pcm_hw_params_t structure on the stack. */
169 snd_pcm_hw_params_alloca(&hwparams);
170 snd_pcm_hw_params_current(pcm_handle, hwparams);
173 snd_pcm_hw_params_get_channels (hwparams, &channels);
175 /* get buffer size */
176 snd_pcm_hw_params_get_buffer_size (hwparams, &buffer_size);
181 /* allocate buffer assuming 2 bytes per sample */
182 buffer_size_bytes = buffer_size * channels * 2;
183 buffer = alloca (buffer_size_bytes);
184 memset (buffer, 0, buffer_size_bytes);
187 snd_pcm_writei(pcm_handle, buffer, buffer_size);
191 static snd_pcm_t * alsa_open_r(const char *pcmdev,int bits,int stereo,int rate)
193 snd_pcm_t *pcm_handle;
196 ms_message("alsa_open_r: opening %s at %iHz, bits=%i, stereo=%i",pcmdev,rate,bits,stereo);
199 #ifndef THREADED_VERSION
200 if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_CAPTURE,SND_PCM_NONBLOCK) < 0) {
201 ms_warning("alsa_open_r: Error opening PCM device %s",pcmdev );
205 /* want blocking mode for threaded version */
206 if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_CAPTURE,0) < 0) {
207 ms_warning("alsa_open_r: Error opening PCM device %s",pcmdev );
217 err = gettimeofday(&tv1, &tz);
219 if (!(alsa_set_params(pcm_handle,0,bits,stereo,rate)<0)){
220 ms_message("alsa_open_r: Audio params set");
223 if (!gettimeofday(&tv2, &tz) && !err) {
224 diff = ((tv2.tv_sec - tv1.tv_sec) * 1000000) + (tv2.tv_usec - tv1.tv_usec);
228 if ((diff < 0) || (diff > 3000000)) { /* 3 secondes */
229 ms_error("alsa_open_r: Error setting params for more than 3 seconds");
230 snd_pcm_close(pcm_handle);
233 ms_warning("alsa_open_r: Error setting params (for %d micros)", diff);
238 err=snd_pcm_start(pcm_handle);
240 ms_warning("snd_pcm_start() failed: %s", snd_strerror(err));
245 static snd_pcm_t * alsa_open_w(const char *pcmdev,int bits,int stereo,int rate)
247 snd_pcm_t *pcm_handle;
249 if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_PLAYBACK,SND_PCM_NONBLOCK) < 0) {
250 ms_warning("alsa_open_w: Error opening PCM device %s",pcmdev );
260 err = gettimeofday(&tv1, &tz);
262 if (!(alsa_set_params(pcm_handle,1,bits,stereo,rate)<0)){
263 ms_message("alsa_open_w: Audio params set");
266 if (!gettimeofday(&tv2, &tz) && !err) {
267 diff = ((tv2.tv_sec - tv1.tv_sec) * 1000000) + (tv2.tv_usec - tv1.tv_usec);
271 if ((diff < 0) || (diff > 3000000)) { /* 3 secondes */
272 ms_error("alsa_open_w: Error setting params for more than 3 seconds");
273 snd_pcm_close(pcm_handle);
276 ms_warning("alsa_open_w: Error setting params (for %d micros)", diff);
284 static int alsa_can_read(snd_pcm_t *dev)
286 snd_pcm_sframes_t avail;
289 avail = snd_pcm_avail_update(dev);
290 /* A buggy driver does not return an error while being in Xrun */
291 if (avail >= 0 && snd_pcm_state(dev) == SND_PCM_STATE_XRUN) avail=-EPIPE;
293 ms_error("snd_pcm_avail_update: %s", snd_strerror(avail)); // most probably -EPIPE
294 /* overrun occured, snd_pcm_state() would return SND_PCM_STATE_XRUN
295 FIXME: handle other error conditions*/
296 ms_error("*** alsa_can_read fixup, trying to recover");
297 snd_pcm_drain(dev); /* Ignore possible error, at least -EAGAIN.*/
298 err = snd_pcm_recover(dev, avail, 0);
300 ms_error("snd_pcm_recover() failed with err %d: %s", err, snd_strerror(err));
303 err = snd_pcm_start(dev);
305 ms_error("snd_pcm_start() failed with err %d: %s", err, snd_strerror(err));
308 ms_message("Recovery done");
313 static int alsa_read(snd_pcm_t *handle,unsigned char *buf,int nsamples)
316 err=snd_pcm_readi(handle,buf,nsamples);
318 ms_warning("alsa_read: snd_pcm_readi() returned %i",err);
320 snd_pcm_prepare(handle);
321 err=snd_pcm_readi(handle,buf,nsamples);
322 if (err<0) ms_warning("alsa_read: snd_pcm_readi() failed:%s.",snd_strerror(err));
323 }else if (err!=-EWOULDBLOCK){
324 ms_warning("alsa_read: snd_pcm_readi() failed:%s.",snd_strerror(err));
327 ms_warning("alsa_read: snd_pcm_readi() returned 0");
333 static int alsa_write(snd_pcm_t *handle,unsigned char *buf,int nsamples)
336 if ((err=snd_pcm_writei(handle,buf,nsamples))<0){
338 snd_pcm_prepare(handle);
340 alsa_fill_w (handle);
342 err=snd_pcm_writei(handle,buf,nsamples);
343 if (err<0) ms_warning("alsa_card_write: Error writing sound buffer (nsamples=%i):%s",nsamples,snd_strerror(err));
344 }else if (err!=-EWOULDBLOCK){
345 ms_warning("alsa_card_write: snd_pcm_writei() failed:%s.",snd_strerror(err));
347 }else if (err!=nsamples) {
348 ms_debug("Only %i samples written instead of %i",err,nsamples);
354 static snd_mixer_t *alsa_mixer_open(const char *mixdev){
355 snd_mixer_t *mixer=NULL;
357 err=snd_mixer_open(&mixer,0);
359 ms_warning("Could not open alsa mixer: %s",snd_strerror(err));
362 if ((err = snd_mixer_attach (mixer, mixdev)) < 0){
363 ms_warning("Could not attach mixer to card: %s",snd_strerror(err));
364 snd_mixer_close(mixer);
367 if ((err = snd_mixer_selem_register (mixer, NULL, NULL)) < 0){
368 ms_warning("snd_mixer_selem_register: %s",snd_strerror(err));
369 snd_mixer_close(mixer);
372 if ((err = snd_mixer_load (mixer)) < 0){
373 ms_warning("snd_mixer_load: %s",snd_strerror(err));
374 snd_mixer_close(mixer);
380 static void alsa_mixer_close(snd_mixer_t *mix){
381 snd_mixer_close(mix);
384 typedef enum {CAPTURE, PLAYBACK, CAPTURE_SWITCH, PLAYBACK_SWITCH} MixerAction;
386 static int get_mixer_element(snd_mixer_t *mixer,const char *name, MixerAction action){
388 const char *elemname;
389 snd_mixer_elem_t *elem;
394 elem=snd_mixer_first_elem(mixer);
396 elemname=snd_mixer_selem_get_name(elem);
397 //ms_message("Found alsa mixer element %s.",elemname);
398 if (strcmp(elemname,name)==0){
401 if (snd_mixer_selem_has_capture_volume(elem)){
402 snd_mixer_selem_get_capture_volume_range(elem, &sndMixerPMin, &sndMixerPMax);
403 err=snd_mixer_selem_get_capture_volume(elem,SND_MIXER_SCHN_UNKNOWN,&newvol);
404 newvol-=sndMixerPMin;
405 value=(100*newvol)/(sndMixerPMax-sndMixerPMin);
406 if (err<0) ms_warning("Could not get capture volume for %s:%s",name,snd_strerror(err));
407 //else ms_message("Successfully get capture level for %s.",elemname);
412 if (snd_mixer_selem_has_playback_volume(elem)){
413 snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);
414 err=snd_mixer_selem_get_playback_volume(elem,SND_MIXER_SCHN_FRONT_LEFT,&newvol);
415 newvol-=sndMixerPMin;
416 value=(100*newvol)/(sndMixerPMax-sndMixerPMin);
417 if (err<0) ms_warning("Could not get playback volume for %s:%s",name,snd_strerror(err));
418 //else ms_message("Successfully get playback level for %s.",elemname);
425 case PLAYBACK_SWITCH:
430 elem=snd_mixer_elem_next(elem);
437 static void set_mixer_element(snd_mixer_t *mixer,const char *name, int level,MixerAction action){
438 const char *elemname;
439 snd_mixer_elem_t *elem;
444 elem=snd_mixer_first_elem(mixer);
447 elemname=snd_mixer_selem_get_name(elem);
448 //ms_message("Found alsa mixer element %s.",elemname);
449 if (strcmp(elemname,name)==0){
452 if (snd_mixer_selem_has_capture_volume(elem)){
453 snd_mixer_selem_get_capture_volume_range(elem, &sndMixerPMin, &sndMixerPMax);
454 newvol=(((sndMixerPMax-sndMixerPMin)*level)/100)+sndMixerPMin;
455 snd_mixer_selem_set_capture_volume_all(elem,newvol);
456 //ms_message("Successfully set capture level for %s.",elemname);
461 if (snd_mixer_selem_has_playback_volume(elem)){
462 snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);
463 newvol=(((sndMixerPMax-sndMixerPMin)*level)/100)+sndMixerPMin;
464 snd_mixer_selem_set_playback_volume_all(elem,newvol);
465 //ms_message("Successfully set playback level for %s.",elemname);
470 if (snd_mixer_selem_has_capture_switch(elem)){
471 snd_mixer_selem_set_capture_switch_all(elem,level);
472 //ms_message("Successfully set capture switch for %s.",elemname);
475 case PLAYBACK_SWITCH:
476 if (snd_mixer_selem_has_playback_switch(elem)){
477 snd_mixer_selem_set_playback_switch_all(elem,level);
478 //ms_message("Successfully set capture switch for %s.",elemname);
484 elem=snd_mixer_elem_next(elem);
491 static void alsa_card_set_level(MSSndCard *obj,MSSndCardMixerElem e,int a)
494 AlsaData *ad=(AlsaData*)obj->data;
495 mixer=alsa_mixer_open(ad->mixdev);
496 if (mixer==NULL) return ;
498 case MS_SND_CARD_MASTER:
499 set_mixer_element(mixer,"Master",a,PLAYBACK);
501 case MS_SND_CARD_CAPTURE:
502 set_mixer_element(mixer,"Capture",a,CAPTURE);
504 case MS_SND_CARD_PLAYBACK:
505 set_mixer_element(mixer,"PCM",a,PLAYBACK);
508 ms_warning("alsa_card_set_level: unsupported command.");
510 alsa_mixer_close(mixer);
513 static int alsa_card_get_level(MSSndCard *obj, MSSndCardMixerElem e)
516 AlsaData *ad=(AlsaData*)obj->data;
518 mixer=alsa_mixer_open(ad->mixdev);
519 if (mixer==NULL) return 0;
521 case MS_SND_CARD_MASTER:
522 value=get_mixer_element(mixer,"Master",PLAYBACK);
524 case MS_SND_CARD_CAPTURE:
525 value=get_mixer_element(mixer,"Capture",CAPTURE);
527 case MS_SND_CARD_PLAYBACK:
528 value=get_mixer_element(mixer,"PCM",PLAYBACK);
531 ms_warning("alsa_card_set_level: unsupported command.");
533 alsa_mixer_close(mixer);
537 static void alsa_card_set_source(MSSndCard *obj,MSSndCardCapture source)
540 AlsaData *ad=(AlsaData*)obj->data;
541 mixer=alsa_mixer_open(ad->mixdev);
542 if (mixer==NULL) return;
544 case MS_SND_CARD_MIC:
545 set_mixer_element(mixer,"Mic",1,CAPTURE_SWITCH);
546 set_mixer_element(mixer,"Capture",1,CAPTURE_SWITCH);
548 case MS_SND_CARD_LINE:
549 set_mixer_element(mixer,"Line",1,CAPTURE_SWITCH);
550 set_mixer_element(mixer,"Capture",1,CAPTURE_SWITCH);
553 alsa_mixer_close(mixer);
556 static MSFilter *alsa_card_create_reader(MSSndCard *card)
558 AlsaData *ad=(AlsaData*)card->data;
559 MSFilter *f=ms_alsa_read_new(ad->pcmdev);
563 static MSFilter *alsa_card_create_writer(MSSndCard *card)
565 AlsaData *ad=(AlsaData*)card->data;
566 MSFilter *f=ms_alsa_write_new(ad->pcmdev);
571 static void alsa_card_init(MSSndCard *obj){
572 AlsaData *ad=ms_new0(AlsaData,1);
576 static void alsa_card_uninit(MSSndCard *obj){
577 AlsaData *ad=(AlsaData*)obj->data;
578 if (ad->pcmdev!=NULL) ms_free(ad->pcmdev);
579 if (ad->mixdev!=NULL) ms_free(ad->mixdev);
583 static void alsa_card_detect(MSSndCardManager *m){
586 MSSndCard *card=alsa_card_new(i);
588 ms_snd_card_manager_add_card(m,card);
592 MSSndCardDesc alsa_card_desc={
594 .detect=alsa_card_detect,
595 .init=alsa_card_init,
596 .set_level=alsa_card_set_level,
597 .get_level=alsa_card_get_level,
598 .set_capture=alsa_card_set_source,
601 .create_reader=alsa_card_create_reader,
602 .create_writer=alsa_card_create_writer,
603 .uninit=alsa_card_uninit,
604 .duplicate=alsa_card_duplicate
607 static MSSndCard *alsa_card_duplicate(MSSndCard *obj){
608 MSSndCard *card=ms_snd_card_new(&alsa_card_desc);
609 AlsaData* dcard=(AlsaData*)card->data;
610 AlsaData* dobj=(AlsaData*)obj->data;
611 card->name=ms_strdup(obj->name);
612 card->id=ms_strdup(obj->id);
613 dcard->pcmdev=ms_strdup(dobj->pcmdev);
614 dcard->mixdev=ms_strdup(dobj->mixdev);
618 MSSndCard * ms_alsa_card_new_custom(const char *pcmdev, const char *mixdev){
621 obj=ms_snd_card_new(&alsa_card_desc);
622 ad=(AlsaData*)obj->data;
623 obj->name=ms_strdup(pcmdev);
624 ad->pcmdev=ms_strdup(pcmdev);
625 ad->mixdev=ms_strdup(mixdev);
629 static unsigned int get_card_capabilities(const char *devname){
630 snd_pcm_t *pcm_handle;
632 if (snd_pcm_open(&pcm_handle,devname,SND_PCM_STREAM_CAPTURE,SND_PCM_NONBLOCK)==0) {
633 ret|=MS_SND_CARD_CAP_CAPTURE;
634 snd_pcm_close(pcm_handle);
636 if (snd_pcm_open(&pcm_handle,devname,SND_PCM_STREAM_PLAYBACK,SND_PCM_NONBLOCK)==0) {
637 ret|=MS_SND_CARD_CAP_PLAYBACK;
638 snd_pcm_close(pcm_handle);
643 static MSSndCard * alsa_card_new(int id)
651 err=snd_card_get_name(id,&name);
656 obj=ms_snd_card_new(&alsa_card_desc);
657 ad=(AlsaData*)obj->data;
659 /* the default pcm device */
660 obj->name=ms_strdup("default device");
661 ad->pcmdev=ms_strdup("default");
662 ad->mixdev=ms_strdup("default");
664 /* remove trailing spaces from card name */
666 pos1=ms_strdup(name);
667 pos2=pos1+strlen(pos1)-1;
668 for (; pos2>pos1 && *pos2==' '; pos2--) *pos2='\0';
670 ad->pcmdev=ms_strdup_printf("default:%i",id);
671 ad->mixdev=ms_strdup_printf("default:%i",id);
674 mixer = alsa_mixer_open(ad->mixdev);
677 ad->mixdev=ms_strdup_printf("hw:%i",id);
679 alsa_mixer_close(mixer);
683 /*check card capabilities: */
684 obj->capabilities=get_card_capabilities(ad->pcmdev);
685 if (obj->capabilities==0){
686 ms_warning("Strange, sound card %s does not seems to be capable of anything, retrying with plughw...",obj->name);
687 /*retry with plughw: this workarounds an alsa bug*/
689 ad->pcmdev=ms_strdup_printf("plughw:%i",id);
690 obj->capabilities=get_card_capabilities(ad->pcmdev);
691 if (obj->capabilities==0){
692 ms_warning("Strange, sound card %s seems totally unusable.",obj->name);
696 /*ms_message("alsa device %s found",obj->name);*/
700 struct _AlsaReadData{
706 #ifdef THREADED_VERSION
709 MSBufferizer * bufferizer;
711 bool_t write_started;
715 typedef struct _AlsaReadData AlsaReadData;
717 void alsa_read_init(MSFilter *obj){
718 AlsaReadData *ad=ms_new(AlsaReadData,1);
725 #ifdef THREADED_VERSION
726 ad->read_started=FALSE;
727 ad->write_started=FALSE;
728 ad->bufferizer=ms_bufferizer_new();
729 ms_mutex_init(&ad->mutex,NULL);
734 #ifdef THREADED_VERSION
736 static void * alsa_write_thread(void *p){
737 AlsaReadData *ad=(AlsaReadData*)p;
738 int samples=(160*ad->rate)/8000;
742 struct timeval timeout;
743 if (ad->handle==NULL && ad->pcmdev!=NULL){
744 ad->handle=alsa_open_r(ad->pcmdev,16,ad->nchannels==2,ad->rate);
746 if (ad->handle==NULL) return NULL;
748 while (ad->read_started)
750 count = alsa_can_read(ad->handle,samples);
752 { /* keep this value for this driver */ }
759 //ms_warning("%i count", count);
766 if ((err=alsa_read(ad->handle,om->b_wptr,count))<=0)
768 ms_warning("nothing to read");
769 //ms_warning("Fail to read samples %i", count);
770 freemsg(om); /* leak fixed */
773 //ms_warning(" read %i", err);
778 ms_mutex_lock(&ad->mutex);
779 ms_bufferizer_put(ad->bufferizer,om);
780 ms_mutex_unlock(&ad->mutex);
785 timeout.tv_usec = 2000;
786 select(0, 0, NULL, NULL, &timeout );
790 /* select will be less active than locking on "read" */
792 timeout.tv_usec = 5000;
793 select(0, 0, NULL, NULL, &timeout );
797 if (ad->handle!=NULL) snd_pcm_close(ad->handle);
802 static void alsa_start_r(AlsaReadData *d){
803 if (d->read_started==FALSE){
804 d->read_started=TRUE;
805 ms_thread_create(&d->thread,NULL,alsa_write_thread,d);
806 }else d->read_started=TRUE;
809 static void alsa_stop_r(AlsaReadData *d){
810 d->read_started=FALSE;
813 ms_thread_join(d->thread,NULL);
819 #ifdef THREADED_VERSION
820 void alsa_read_preprocess(MSFilter *obj){
821 AlsaReadData *ad=(AlsaReadData*)obj->data;
826 void alsa_read_postprocess(MSFilter *obj){
827 AlsaReadData *ad=(AlsaReadData*)obj->data;
828 #ifdef THREADED_VERSION
831 if (ad->handle!=NULL) snd_pcm_close(ad->handle);
835 void alsa_read_uninit(MSFilter *obj){
836 AlsaReadData *ad=(AlsaReadData*)obj->data;
837 #ifdef THREADED_VERSION
840 if (ad->pcmdev!=NULL) ms_free(ad->pcmdev);
841 if (ad->handle!=NULL) snd_pcm_close(ad->handle);
842 #ifdef THREADED_VERSION
843 ms_bufferizer_destroy(ad->bufferizer);
844 ms_mutex_destroy(&ad->mutex);
849 #ifndef THREADED_VERSION
850 void alsa_read_process(MSFilter *obj){
851 AlsaReadData *ad=(AlsaReadData*)obj->data;
852 int samples=(128*ad->rate)/8000;
855 if (ad->handle==NULL && ad->pcmdev!=NULL){
856 ad->handle=alsa_open_r(ad->pcmdev,16,ad->nchannels==2,ad->rate);
858 if (ad->handle==NULL) return;
859 while (alsa_can_read(ad->handle)>=samples){
863 if ((err=alsa_read(ad->handle,om->b_wptr,samples))<=0) {
864 ms_warning("Fail to read samples");
870 /*ms_message("alsa_read_process: Outputing %i bytes",size);*/
871 ms_queue_put(obj->outputs[0],om);
876 #ifdef THREADED_VERSION
877 void alsa_read_process(MSFilter *obj){
878 AlsaReadData *ad=(AlsaReadData*)obj->data;
880 int samples=(160*ad->rate)/8000;
882 ms_mutex_lock(&ad->mutex);
883 while (ms_bufferizer_get_avail(ad->bufferizer)>=samples*2){
885 om=allocb(samples*2,0);
886 ms_bufferizer_read(ad->bufferizer,om->b_wptr,samples*2);
887 om->b_wptr+=samples*2;
888 /*ms_message("alsa_read_process: Outputing %i bytes",size);*/
889 ms_queue_put(obj->outputs[0],om);
891 ms_mutex_unlock(&ad->mutex);
895 static int alsa_read_get_sample_rate(MSFilter *obj, void *param){
896 AlsaReadData *ad=(AlsaReadData*)obj->data;
897 *((int*)param)=ad->rate;
901 static int alsa_read_set_sample_rate(MSFilter *obj, void *param){
902 AlsaReadData *ad=(AlsaReadData*)obj->data;
903 ad->rate=*((int*)param);
907 static int alsa_read_set_nchannels(MSFilter *obj, void *param){
908 AlsaReadData *ad=(AlsaReadData*)obj->data;
909 ad->nchannels=*((int*)param);
913 MSFilterMethod alsa_read_methods[]={
914 {MS_FILTER_GET_SAMPLE_RATE, alsa_read_get_sample_rate},
915 {MS_FILTER_SET_SAMPLE_RATE, alsa_read_set_sample_rate},
916 {MS_FILTER_SET_NCHANNELS, alsa_read_set_nchannels},
920 MSFilterDesc alsa_read_desc={
923 .text=N_("Alsa sound source"),
924 .category=MS_FILTER_OTHER,
927 .init=alsa_read_init,
928 #ifdef THREADED_VERSION
929 .preprocess=alsa_read_preprocess,
931 .process=alsa_read_process,
932 .postprocess=alsa_read_postprocess,
933 .uninit=alsa_read_uninit,
934 .methods=alsa_read_methods
937 static MSFilter * ms_alsa_read_new(const char *dev){
938 MSFilter *f=ms_filter_new_from_desc(&alsa_read_desc);
939 AlsaReadData *ad=(AlsaReadData*)f->data;
940 ad->pcmdev=ms_strdup(dev);
944 typedef struct _AlsaReadData AlsaWriteData;
946 void alsa_write_init(MSFilter *obj){
947 AlsaWriteData *ad=ms_new(AlsaWriteData,1);
955 void alsa_write_postprocess(MSFilter *obj){
956 AlsaReadData *ad=(AlsaReadData*)obj->data;
957 if (ad->handle!=NULL) snd_pcm_close(ad->handle);
961 void alsa_write_uninit(MSFilter *obj){
962 AlsaWriteData *ad=(AlsaWriteData*)obj->data;
963 if (ad->pcmdev!=NULL) ms_free(ad->pcmdev);
964 if (ad->handle!=NULL) snd_pcm_close(ad->handle);
968 static int alsa_write_get_sample_rate(MSFilter *obj, void *data){
969 AlsaWriteData *ad=(AlsaWriteData*)obj->data;
970 *((int*)data)=ad->rate;
974 int alsa_write_set_sample_rate(MSFilter *obj, void *data){
975 int *rate=(int*)data;
976 AlsaWriteData *ad=(AlsaWriteData*)obj->data;
981 int alsa_write_set_nchannels(MSFilter *obj, void *data){
983 AlsaWriteData *ad=(AlsaWriteData*)obj->data;
988 void alsa_write_process(MSFilter *obj){
989 AlsaWriteData *ad=(AlsaWriteData*)obj->data;
994 if (ad->handle==NULL && ad->pcmdev!=NULL){
995 ad->handle=alsa_open_w(ad->pcmdev,16,ad->nchannels==2,ad->rate);
997 alsa_fill_w (ad->pcmdev);
1000 if (ad->handle==NULL) {
1001 ms_queue_flush(obj->inputs[0]);
1004 while ((im=ms_queue_get(obj->inputs[0]))!=NULL){
1005 while((size=im->b_wptr-im->b_rptr)>0){
1006 samples=size/(2*ad->nchannels);
1007 err=alsa_write(ad->handle,im->b_rptr,samples);
1009 im->b_rptr+=err*(2*ad->nchannels);
1017 MSFilterMethod alsa_write_methods[]={
1018 {MS_FILTER_GET_SAMPLE_RATE, alsa_write_get_sample_rate},
1019 {MS_FILTER_SET_SAMPLE_RATE, alsa_write_set_sample_rate},
1020 {MS_FILTER_SET_NCHANNELS, alsa_write_set_nchannels},
1024 MSFilterDesc alsa_write_desc={
1025 .id=MS_ALSA_WRITE_ID,
1026 .name="MSAlsaWrite",
1027 .text=N_("Alsa sound output"),
1028 .category=MS_FILTER_OTHER,
1031 .init=alsa_write_init,
1032 .process=alsa_write_process,
1033 .postprocess=alsa_write_postprocess,
1034 .uninit=alsa_write_uninit,
1035 .methods=alsa_write_methods
1039 static MSFilter * ms_alsa_write_new(const char *dev){
1040 MSFilter *f=ms_filter_new_from_desc(&alsa_write_desc);
1041 AlsaWriteData *ad=(AlsaWriteData*)f->data;
1042 ad->pcmdev=ms_strdup(dev);
1047 MS_FILTER_DESC_EXPORT(alsa_write_desc)
1049 MS_FILTER_DESC_EXPORT(alsa_read_desc)