]> sjero.net Git - linphone/blob - linphone/mediastreamer2/src/pasnd.c
remote ortp and add it as a submodule instead.
[linphone] / linphone / mediastreamer2 / src / pasnd.c
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 #include <speex/speex_preprocess.h>
21
22 #include "mediastreamer2/mssndcard.h"
23 #include "mediastreamer2/msfilter.h"
24
25 #include "portaudio.h"
26
27 MSFilter *ms_pasnd_read_new(MSSndCard *card);
28 MSFilter *ms_pasnd_write_new(MSSndCard *card);
29
30 typedef struct PASndData{
31   char *pcmdev;
32   char *mixdev;
33   int sound_err;
34   char waveoutbuffer[30][3200];
35   PaStream   *waveoutdev;
36   
37   PaStream   *waveindev;
38   
39   int rate;
40   int bits;
41   ms_thread_t thread;
42   ms_mutex_t mutex;
43   queue_t rq;
44   MSBufferizer * bufferizer;
45   bool_t read_started;
46   bool_t write_started;
47   bool_t stereo;
48
49   SpeexPreprocessState *pst;
50 } PASndData;
51
52 int SpeakerCallback(  const void *inputBuffer, void *outputBuffer,
53                       unsigned long framesPerBuffer,
54                       const PaStreamCallbackTimeInfo* timeInfo,
55                       PaStreamCallbackFlags statusFlags,
56                       void *userData )
57 {
58   PASndData *device = (PASndData*)userData;
59   uint8_t *wtmpbuff=NULL;
60   int err;
61   int ovfl = (device->rate/8000)*320*6;
62
63   memset(outputBuffer,0, framesPerBuffer*2);
64   if (!device->read_started && !device->write_started)
65     {
66       return 0;
67     }
68
69   wtmpbuff=(uint8_t*)alloca(framesPerBuffer*2);
70
71   memset(outputBuffer,0, framesPerBuffer*2);
72
73   ms_mutex_lock(&device->mutex);
74
75   /* remove extra buffer when latency is increasing:
76      this often happen with USB device */
77   if (device->bufferizer->size>=ovfl){
78     ms_warning("Extra data for sound card (total:%i %ims)",
79                device->bufferizer->size, (device->bufferizer->size*20)/320);
80     err=ms_bufferizer_read(device->bufferizer,wtmpbuff, framesPerBuffer*2);
81     err=ms_bufferizer_read(device->bufferizer,wtmpbuff, framesPerBuffer*2);
82     err=ms_bufferizer_read(device->bufferizer,wtmpbuff, framesPerBuffer*2);
83     err=ms_bufferizer_read(device->bufferizer,wtmpbuff, framesPerBuffer*2);
84     err=ms_bufferizer_read(device->bufferizer,wtmpbuff, framesPerBuffer*2);
85     ms_warning("Extra data for sound card removed (total:%i %ims)",
86                device->bufferizer->size, (device->bufferizer->size*20)/320);
87   }
88
89   err=ms_bufferizer_read(device->bufferizer,wtmpbuff,framesPerBuffer*2);
90   ms_mutex_unlock(&device->mutex);
91   if (err==framesPerBuffer*2)
92     {
93       memcpy (outputBuffer, wtmpbuff, framesPerBuffer*2);
94     }
95
96   return 0;
97 }
98
99 int WaveInCallback(  const void *inputBuffer, void *outputBuffer,
100                      unsigned long framesPerBuffer,
101                      const PaStreamCallbackTimeInfo* timeInfo,
102                      PaStreamCallbackFlags statusFlags,
103                      void *userData )
104 {
105   PASndData *device = (PASndData*)userData;
106
107   if (!device->read_started && !device->write_started)
108     {
109       return 0;
110     }
111
112   ms_mutex_lock(&device->mutex);
113   if (device->read_started)
114     {
115       int vad;
116       mblk_t *rm=NULL;
117       if (rm==NULL) rm=allocb(framesPerBuffer*2,0);
118       memcpy(rm->b_wptr,inputBuffer, framesPerBuffer*2);
119       
120       if (device->pst!=NULL)
121         {
122           vad = speex_preprocess(device->pst, (spx_int16_t *)rm->b_wptr, NULL);
123 #if 0
124           if (vad!=1)
125             ms_message("WaveInCallback : %d", vad);
126 #endif
127         }
128       
129       rm->b_wptr+=framesPerBuffer*2;
130       
131       putq(&device->rq,rm);
132       rm=NULL;
133     }
134   ms_mutex_unlock(&device->mutex);
135
136   return 0;
137 }
138
139 static int pasnd_open(PASndData *device, int devnumber, int bits,int stereo, int rate, int *minsz)
140 {
141     PaStreamParameters outputParameters;
142     PaStreamParameters inputParameters;
143     PaError err;
144
145     const PaHostApiInfo *pa_hai = Pa_GetHostApiInfo(Pa_GetDefaultHostApi());
146     
147     ms_warning("pasnd_open : opening default input device: name=%s (%i)",
148                pa_hai->name, pa_hai->defaultInputDevice);
149     ms_warning("pasnd_open : opening default output device name=%s (%i)",
150                pa_hai->name, pa_hai->defaultOutputDevice);
151
152     outputParameters.device = devnumber; /* default output device */
153     outputParameters.device = pa_hai->defaultOutputDevice;
154     outputParameters.channelCount = 1;       /* stereo output */
155     outputParameters.sampleFormat = paInt16; /* 32 bit floating point output */
156     outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
157     outputParameters.hostApiSpecificStreamInfo = NULL;
158
159     err = Pa_OpenStream(
160                         &device->waveoutdev,    /* stream */
161                         NULL,                   /* no input */
162                         &outputParameters,      //
163                         rate,                   // double sampleRate
164                         160*(rate/8000),        //unsigned long framesPerBuffer
165                         paClipOff,
166                         SpeakerCallback,        //PortAudioCallback *callback
167                         (void *) device);       //void *userData
168
169     if (err != paNoError)
170     {
171         ms_warning("Failed to open out device. (Pa_OpenDefaultStream:0x%i)", err);
172         return -1;
173     }
174
175     inputParameters.device = devnumber; /* default input device */
176     inputParameters.device = pa_hai->defaultInputDevice;
177     inputParameters.channelCount = 1;       /* stereo input */
178     inputParameters.sampleFormat = paInt16; /* 32 bit floating point input */
179     inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
180     inputParameters.hostApiSpecificStreamInfo = NULL;
181
182     err = Pa_OpenStream(
183                         &device->waveindev,     //PortAudioStream** stream
184                         &inputParameters,       /* input param*/
185                         NULL,                   /* output param */
186                         rate,                   // double sampleRate
187                         160*(rate/8000),        //unsigned long framesPerBuffer
188                         paClipOff,
189                         WaveInCallback,         //PortAudioCallback *callback
190                         (void *) device);       //void *userData
191
192         
193     if (err != paNoError)
194     {
195         ms_warning("Failed to open in device. (Pa_OpenDefaultStream:0x%i)", err);
196         return -1;
197     }
198
199     err = Pa_StartStream( device->waveoutdev );
200     if( err != paNoError )
201       {
202         ms_warning("Failed to start out device. (Pa_StartStream:0x%i)", err);
203         return -1;
204       }
205
206         device->pst = speex_preprocess_state_init((device->rate/8000 * 320)/2, device->rate);
207         if (device->pst!=NULL) {
208                 float f;
209                 int i=1;
210                 speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_VAD, &i);
211                 i=1;
212                 speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DENOISE, &i);
213                 i=0;
214                 speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_AGC, &i);
215                 f=8000;
216                 speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_AGC_LEVEL, &f);
217                 i=0;
218                 speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DEREVERB, &i);
219                 f=.4;
220                 speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f);
221                 f=.3;
222                 speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f);
223         }
224
225     err = Pa_StartStream( device->waveindev );
226     if( err != paNoError )
227       {
228         ms_warning("Failed to start in device: trying default device. (Pa_StartStream:0x%i)", err);
229         return -1;
230       }
231
232         *minsz=device->rate/8000 * 320;
233         return 0;
234 }
235
236 static void pasnd_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent)
237 {
238         PASndData *d=(PASndData*)card->data;
239
240         if (d->mixdev==NULL) return;
241         switch(e){
242         case MS_SND_CARD_MASTER:
243           return;
244           break;
245         case MS_SND_CARD_CAPTURE:
246           break;
247         case MS_SND_CARD_PLAYBACK:
248           break;
249         default:
250           ms_warning("pasnd_card_set_level: unsupported command.");
251           return;
252         }
253 }
254
255 static int pasnd_get_level(MSSndCard *card, MSSndCardMixerElem e)
256 {
257         PASndData *d=(PASndData*)card->data;
258
259         if (d->mixdev==NULL) return -1;
260         switch(e){
261         case MS_SND_CARD_MASTER:
262           return 60;
263           break;
264         case MS_SND_CARD_CAPTURE:
265           break;
266         case MS_SND_CARD_PLAYBACK:
267           break;
268         default:
269           ms_warning("pasnd_card_get_level: unsupported command.");
270           return -1;
271         }
272         return -1;
273 }
274
275 static void pasnd_set_source(MSSndCard *card, MSSndCardCapture source)
276 {
277         PASndData *d=(PASndData*)card->data;
278         if (d->mixdev==NULL) return;
279
280         switch(source){
281                 case MS_SND_CARD_MIC:
282                 break;
283                 case MS_SND_CARD_LINE:
284                 break;
285         }       
286 }
287
288 static void pasnd_init(MSSndCard *card){
289         PASndData *d=ms_new(PASndData,1);
290         memset(d, 0, sizeof(PASndData));
291         d->pcmdev=NULL;
292         d->mixdev=NULL;
293         d->sound_err=-1; /* not opened */
294         d->read_started=FALSE;
295         d->write_started=FALSE;
296         d->bits=16;
297         d->rate=8000;
298         d->stereo=FALSE;
299         qinit(&d->rq);
300         d->bufferizer=ms_bufferizer_new();
301         ms_mutex_init(&d->mutex,NULL);
302         card->data=d;
303         d->pst=0;
304 }
305
306 static void pasnd_uninit(MSSndCard *card){
307         PASndData *d=(PASndData*)card->data;
308         if (d==NULL)
309                 return;
310         if (d->pcmdev!=NULL) ms_free(d->pcmdev);
311         if (d->mixdev!=NULL) ms_free(d->mixdev);
312         ms_bufferizer_destroy(d->bufferizer);
313         flushq(&d->rq,0);
314
315         ms_mutex_destroy(&d->mutex);
316
317         if (d->pst!=NULL)
318             speex_preprocess_state_destroy(d->pst);
319
320         ms_free(d);
321 }
322
323 #define DSP_NAME "/dev/dsp"
324 #define MIXER_NAME "/dev/mixer"
325
326 static void pasnd_detect(MSSndCardManager *m);
327 static MSSndCard *pasnd_duplicate(MSSndCard *obj);
328
329 MSSndCardDesc pasnd_card_desc={
330         "PASND",
331         pasnd_detect,
332         pasnd_init,
333         pasnd_set_level,
334         pasnd_get_level,
335         pasnd_set_source,
336         NULL,
337         NULL,
338         ms_pasnd_read_new,
339         ms_pasnd_write_new,
340         pasnd_uninit,
341         pasnd_duplicate
342 };
343
344 static MSSndCard *pasnd_duplicate(MSSndCard *obj){
345         MSSndCard *card=ms_snd_card_new(&pasnd_card_desc);
346         PASndData *dcard=(PASndData*)card->data;
347         PASndData *dobj=(PASndData*)obj->data;
348         dcard->pcmdev=ms_strdup(dobj->pcmdev);
349         dcard->mixdev=ms_strdup(dobj->mixdev);
350         card->name=ms_strdup(obj->name);
351         return card;
352 }
353
354 static MSSndCard *pasnd_card_new(const char *pcmdev, const char *mixdev){
355         MSSndCard *card=ms_snd_card_new(&pasnd_card_desc);
356         PASndData *d=(PASndData*)card->data;
357         d->pcmdev=ms_strdup(pcmdev);
358         d->mixdev=ms_strdup(mixdev);
359         card->name=ms_strdup(pcmdev);
360         return card;
361 }
362
363 static void pasnd_detect(MSSndCardManager *m){
364     int err = 0;
365     unsigned int numDevices;
366     const PaDeviceInfo *pdi;
367     char pcmdev[1024];
368     char mixdev[1024];
369     int i;
370
371     err = Pa_Initialize();
372     if( err != paNoError )
373       {
374         ms_warning("PortAudio error: %s\n", Pa_GetErrorText( err ) );
375         return;
376       }
377
378     numDevices = Pa_GetDeviceCount();
379
380     for( i=0; i<numDevices; i++ ) {
381       pdi = Pa_GetDeviceInfo( i );
382       if (pdi!=NULL)
383         {
384           MSSndCard *card;
385           snprintf(pcmdev,sizeof(pcmdev),"%s",pdi->name);
386           snprintf(mixdev,sizeof(mixdev),"%s",pdi->name);
387           if (i == 0)
388             {
389               card=pasnd_card_new(pcmdev,mixdev);
390               ms_snd_card_manager_add_card(m,card);
391             }
392           card=pasnd_card_new(pcmdev,mixdev);
393           ms_snd_card_manager_add_card(m,card);
394         }
395     }
396 }
397
398 static void pasnd_closedriver(PASndData *d)
399 {
400         if (d->sound_err==0) {
401
402           int err = Pa_StopStream( d->waveindev );
403           if( err != paNoError )
404             {
405               ms_warning("Failed to stop device. (Pa_StopStream:0x%i)", err);
406             }
407           
408           err = Pa_CloseStream( d->waveindev);
409           if( err != paNoError )
410             {
411               ms_warning("failed to close recording sound card (Pa_CloseStream:0x%i)", err);
412             }
413           else
414             {
415               ms_message("successfully closed recording sound card");
416             }
417           
418           err = Pa_StopStream( d->waveoutdev );
419           if( err != paNoError )
420             {
421               ms_warning("Failed to stop device. (Pa_StopStream:0x%i)", err);
422             }
423           
424           err = Pa_CloseStream( d->waveoutdev );
425           if( err != paNoError ) 
426             {
427               ms_error("failed to stop recording sound card (Pa_CloseStream:0x%i)", err);
428             }
429           else
430             {
431               ms_message("successfully stopped recording sound card");
432             }
433           
434           
435           d->sound_err=-1;
436         }
437 }
438
439 static void pasnd_start_r(MSSndCard *card){
440         PASndData *d=(PASndData*)card->data;
441         if (d->read_started==FALSE && d->write_started==FALSE){
442                 int bsize=0;
443                 d->read_started=TRUE;
444                 d->sound_err=pasnd_open(d, 0, d->bits,d->stereo,d->rate,&bsize);
445         }else d->read_started=TRUE;
446 }
447
448 static void pasnd_stop_r(MSSndCard *card){
449         PASndData *d=(PASndData*)card->data;
450         d->read_started=FALSE;
451         if (d->write_started==FALSE){
452           /* ms_thread_join(d->thread,NULL); */
453           pasnd_closedriver(d);
454         }
455 }
456
457 static void pasnd_start_w(MSSndCard *card){
458         PASndData *d=(PASndData*)card->data;
459         if (d->read_started==FALSE && d->write_started==FALSE){
460                 int bsize=0;
461                 d->write_started=TRUE;
462                 d->sound_err=pasnd_open(d, 0, d->bits,d->stereo,d->rate,&bsize);
463         }else{
464                 d->write_started=TRUE;
465         }
466 }
467
468 static void pasnd_stop_w(MSSndCard *card){
469         PASndData *d=(PASndData*)card->data;
470         d->write_started=FALSE;
471         if (d->read_started==FALSE){
472           /* ms_thread_join(d->thread,NULL); */
473           pasnd_closedriver(d);
474         }
475 }
476
477 static mblk_t *pasnd_get(MSSndCard *card){
478         PASndData *d=(PASndData*)card->data;
479         mblk_t *m;
480         ms_mutex_lock(&d->mutex);
481         m=getq(&d->rq);
482         ms_mutex_unlock(&d->mutex);
483         return m;
484 }
485
486 static void pasnd_put(MSSndCard *card, mblk_t *m){
487         PASndData *d=(PASndData*)card->data;
488         ms_mutex_lock(&d->mutex);
489         ms_bufferizer_put(d->bufferizer,m);
490         ms_mutex_unlock(&d->mutex);
491 }
492
493
494 static void pasnd_read_preprocess(MSFilter *f){
495         MSSndCard *card=(MSSndCard*)f->data;
496         pasnd_start_r(card);
497 }
498
499 static void pasnd_read_postprocess(MSFilter *f){
500         MSSndCard *card=(MSSndCard*)f->data;
501         pasnd_stop_r(card);
502 }
503
504 static void pasnd_read_process(MSFilter *f){
505         MSSndCard *card=(MSSndCard*)f->data;
506         mblk_t *m;
507         while((m=pasnd_get(card))!=NULL){
508                 ms_queue_put(f->outputs[0],m);
509         }
510 }
511
512 static void pasnd_write_preprocess(MSFilter *f){
513         MSSndCard *card=(MSSndCard*)f->data;
514         pasnd_start_w(card);
515 }
516
517 static void pasnd_write_postprocess(MSFilter *f){
518         MSSndCard *card=(MSSndCard*)f->data;
519         pasnd_stop_w(card);
520 }
521
522 static void pasnd_write_process(MSFilter *f){
523         MSSndCard *card=(MSSndCard*)f->data;
524         mblk_t *m;
525         while((m=ms_queue_get(f->inputs[0]))!=NULL){
526                 pasnd_put(card,m);
527         }
528 }
529
530 static int set_rate(MSFilter *f, void *arg){
531         MSSndCard *card=(MSSndCard*)f->data;
532         PASndData *d=(PASndData*)card->data;
533         d->rate=*((int*)arg);
534         return 0;
535 }
536
537 static int set_nchannels(MSFilter *f, void *arg){
538         MSSndCard *card=(MSSndCard*)f->data;
539         PASndData *d=(PASndData*)card->data;
540         d->stereo=(*((int*)arg)==2);
541         return 0;
542 }
543
544 static MSFilterMethod pasnd_methods[]={
545         {       MS_FILTER_SET_SAMPLE_RATE       , set_rate      },
546         {       MS_FILTER_SET_NCHANNELS         , set_nchannels },
547         {       0                               , NULL          }
548 };
549
550 MSFilterDesc pasnd_read_desc={
551         MS_PASND_READ_ID,
552         "MSPasndRead",
553         "Sound capture filter for Port Audio Sound drivers",
554         MS_FILTER_OTHER,
555         NULL,
556         0,
557         1,
558         NULL,
559         pasnd_read_preprocess,
560         pasnd_read_process,
561         pasnd_read_postprocess,
562         NULL,
563         pasnd_methods
564 };
565
566
567 MSFilterDesc pasnd_write_desc={
568         MS_PASND_WRITE_ID,
569         "MSPasndWrite",
570         "Sound playback filter for Port Audio Sound drivers",
571         MS_FILTER_OTHER,
572         NULL,
573         1,
574         0,
575         NULL,
576         pasnd_write_preprocess,
577         pasnd_write_process,
578         pasnd_write_postprocess,
579         NULL,
580         pasnd_methods
581 };
582
583 MSFilter *ms_pasnd_read_new(MSSndCard *card){
584         MSFilter *f=ms_filter_new_from_desc(&pasnd_read_desc);
585         f->data=card;
586         return f;
587 }
588
589
590 MSFilter *ms_pasnd_write_new(MSSndCard *card){
591         MSFilter *f=ms_filter_new_from_desc(&pasnd_write_desc);
592         f->data=card;
593         return f;
594 }
595
596 MS_FILTER_DESC_EXPORT(pasnd_read_desc)
597 MS_FILTER_DESC_EXPORT(pasnd_write_desc)