source: mediastreamer2/linphone/mediastreamer2/src/winsnd2.c @ 67:3cc8c5a5785d

Last change on this file since 67:3cc8c5a5785d was 67:3cc8c5a5785d, checked in by aymeric <aymeric@…>, 5 years ago

Fix logs and statistics

git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@70 3f6dc0c8-ddfe-455d-9043-3cd528dc4637

  • Property exe set to *
File size: 20.7 KB
Line 
1/*
2mediastreamer2 library - modular sound and video processing and streaming
3Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18*/
19
20#include "mediastreamer2/mssndcard.h"
21#include "mediastreamer2/msfilter.h"
22#include "mediastreamer2/msticker.h"
23
24#include <mmsystem.h>
25#ifdef _MSC_VER
26#include <mmreg.h>
27#endif
28#include <msacm.h>
29
30#if defined(_WIN32_WCE)
31//#define DISABLE_SPEEX
32//#define WCE_OPTICON_WORKAROUND 1000
33#endif
34#ifndef DISABLE_SPEEX
35#include <speex/speex_preprocess.h>
36#endif
37
38#define WINSND_NBUFS 10
39#define WINSND_OUT_NBUFS 20
40#define WINSND_NSAMPLES 320
41#define WINSND_MINIMUMBUFFER 5
42
43static MSFilter *ms_winsnd_read_new(MSSndCard *card);
44static MSFilter *ms_winsnd_write_new(MSSndCard *card);
45
46typedef struct WinSndCard{
47        int in_devid;
48        int out_devid;
49}WinSndCard;
50
51static void winsndcard_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent){
52    MMRESULT mr = MMSYSERR_NOERROR;
53    DWORD dwVolume = 0xFFFF;
54    dwVolume = ((0xFFFF) * percent) / 100;
55
56        switch(e){
57                case MS_SND_CARD_MASTER:
58            /*mr = waveOutSetVolume(d->waveoutdev, dwVolume); */
59                if (mr != MMSYSERR_NOERROR)
60                {
61                ms_warning("Failed to set master volume. (waveOutSetVolume:0x%i)", mr);
62                return;
63                }
64        break;
65        case MS_SND_CARD_CAPTURE:
66                break;
67                case MS_SND_CARD_PLAYBACK:
68                break;
69        default:
70                        ms_warning("winsnd_card_set_level: unsupported command.");
71        }
72}
73
74static int winsndcard_get_level(MSSndCard *card, MSSndCardMixerElem e){
75        switch(e){
76                case MS_SND_CARD_MASTER:
77            /*mr=waveOutGetVolume(d->waveoutdev, &dwVolume);*/
78            /* Transform to 0 to 100 scale*/
79            /*dwVolume = (dwVolume *100) / (0xFFFF);*/
80            return 60;
81        break;
82        case MS_SND_CARD_CAPTURE:
83                break;
84                case MS_SND_CARD_PLAYBACK:
85                break;
86                default:
87                        ms_warning("winsnd_card_get_level: unsupported command.");
88                        return -1;
89        }
90        return -1;
91}
92
93static void winsndcard_set_source(MSSndCard *card, MSSndCardCapture source){
94
95        switch(source){
96                case MS_SND_CARD_MIC:
97                break;
98                case MS_SND_CARD_LINE:
99                break;
100        }       
101}
102
103static void winsndcard_init(MSSndCard *card){
104        WinSndCard *c=(WinSndCard *)ms_new(WinSndCard,1);
105        card->data=c;
106}
107
108static void winsndcard_uninit(MSSndCard *card){
109        ms_free(card->data);
110}
111
112static void winsndcard_detect(MSSndCardManager *m);
113static  MSSndCard *winsndcard_dup(MSSndCard *obj);
114
115MSSndCardDesc winsnd_card_desc={
116        "WINSND",
117        winsndcard_detect,
118        winsndcard_init,
119        winsndcard_set_level,
120        winsndcard_get_level,
121        winsndcard_set_source,
122        ms_winsnd_read_new,
123        ms_winsnd_write_new,
124        winsndcard_uninit,
125        winsndcard_dup
126};
127
128static  MSSndCard *winsndcard_dup(MSSndCard *obj){
129        MSSndCard *card=ms_snd_card_new(&winsnd_card_desc);
130        card->name=ms_strdup(obj->name);
131        card->data=ms_new(WinSndCard,1);
132        memcpy(card->data,obj->data,sizeof(WinSndCard));
133        return card;
134}
135
136static MSSndCard *winsndcard_new(const char *name, int in_dev, int out_dev, unsigned cap){
137        MSSndCard *card=ms_snd_card_new(&winsnd_card_desc);
138        WinSndCard *d=(WinSndCard*)card->data;
139        card->name=ms_strdup(name);
140        d->in_devid=in_dev;
141        d->out_devid=out_dev;
142        card->capabilities=cap;
143        return card;
144}
145
146static void add_or_update_card(MSSndCardManager *m, const char *name, int indev, int outdev, unsigned int capability){
147        MSSndCard *card;
148        const MSList *elem=ms_snd_card_manager_get_list(m);
149        for(;elem!=NULL;elem=elem->next){
150                card=(MSSndCard*)elem->data;
151                if (strcmp(card->name,name)==0){
152                        /*update already entered card */
153                        WinSndCard *d=(WinSndCard*)card->data;
154                        card->capabilities|=capability;
155                        if (indev!=-1) 
156                                d->in_devid=indev;
157                        if (outdev!=-1)
158                                d->out_devid=outdev;
159                               
160                        return;
161                }
162        }
163        /* add this new card:*/
164        ms_snd_card_manager_add_card(m,winsndcard_new(name,indev,outdev,capability));
165}
166
167static void winsndcard_detect(MSSndCardManager *m){
168    MMRESULT mr = NOERROR;
169    unsigned int nOutDevices = waveOutGetNumDevs ();
170    unsigned int nInDevices = waveInGetNumDevs ();
171    unsigned int item;
172
173    if (nOutDevices>nInDevices)
174                nInDevices = nOutDevices;
175
176    for (item = 0; item < nInDevices; item++){
177               
178        WAVEINCAPS incaps;
179        WAVEOUTCAPS outcaps;
180        mr = waveInGetDevCaps (item, &incaps, sizeof (WAVEINCAPS));
181        if (mr == MMSYSERR_NOERROR)
182                {
183#if defined(_WIN32_WCE)
184                        char card[256];
185                        snprintf(card, sizeof(card), "Input card %i", item);
186                        add_or_update_card(m,card,item,-1,MS_SND_CARD_CAP_CAPTURE);
187                        /* _tprintf(L"new card: %s", incaps.szPname); */
188#else
189                        add_or_update_card(m,incaps.szPname,item,-1,MS_SND_CARD_CAP_CAPTURE);
190#endif
191                }
192        mr = waveOutGetDevCaps (item, &outcaps, sizeof (WAVEOUTCAPS));
193        if (mr == MMSYSERR_NOERROR)
194                {
195#if defined(_WIN32_WCE)
196                        char card[256];
197                        snprintf(card, sizeof(card), "Output card %i", item);
198                add_or_update_card(m,card,-1,item,MS_SND_CARD_CAP_PLAYBACK);
199                        /* _tprintf(L"new card: %s", outcaps.szPname); */
200#else
201                add_or_update_card(m,outcaps.szPname,-1,item,MS_SND_CARD_CAP_PLAYBACK);
202#endif
203                }
204    }
205}
206
207
208typedef struct WinSnd{
209        int dev_id;
210        HWAVEIN indev;
211        HWAVEOUT outdev;
212        WAVEFORMATEX wfx;
213        WAVEHDR hdrs_read[WINSND_NBUFS];
214        WAVEHDR hdrs_write[WINSND_OUT_NBUFS];
215        queue_t rq;
216        ms_mutex_t mutex;
217        unsigned int bytes_read;
218        unsigned int nbufs_playing;
219        bool_t running;
220
221        int32_t stat_input;
222        int32_t stat_output;
223        int32_t stat_notplayed;
224
225        int32_t stat_minimumbuffer;
226
227        queue_t write_rq;
228#ifndef DISABLE_SPEEX
229        SpeexPreprocessState *pst;
230        int pst_frame_size;
231#endif
232        int ready;
233        int workaround; /* workaround for opticon audio device */
234}WinSnd;
235
236static void winsnd_apply_settings(WinSnd *d){
237        d->wfx.nBlockAlign=d->wfx.nChannels*d->wfx.wBitsPerSample/8;
238        d->wfx.nAvgBytesPerSec=d->wfx.nSamplesPerSec*d->wfx.nBlockAlign;
239}
240
241
242#ifndef _TRUE_TIME
243static uint64_t winsnd_get_cur_time( void *data){
244        WinSnd *d=(WinSnd*)data;
245        uint64_t curtime=((uint64_t)d->bytes_read*1000)/(uint64_t)d->wfx.nAvgBytesPerSec;
246        /* ms_debug("winsnd_get_cur_time: bytes_read=%u return %lu\n",d->bytes_read,(unsigned long)curtime); */
247        return curtime;
248}
249#endif
250
251
252static void winsnd_init(MSFilter *f){
253        WinSnd *d=(WinSnd *)ms_new0(WinSnd,1);
254        d->wfx.wFormatTag = WAVE_FORMAT_PCM;
255        d->wfx.cbSize = 0;
256        d->wfx.nAvgBytesPerSec = 16000;
257        d->wfx.nBlockAlign = 2;
258        d->wfx.nChannels = 1;
259        d->wfx.nSamplesPerSec = 8000;
260        d->wfx.wBitsPerSample = 16;
261        qinit(&d->rq);
262        qinit(&d->write_rq);
263#ifndef DISABLE_SPEEX
264        d->pst=NULL;
265        d->pst_frame_size=0;
266#endif
267        d->ready=0;
268        d->workaround=0;
269        ms_mutex_init(&d->mutex,NULL);
270        f->data=d;
271
272        d->stat_input=0;
273        d->stat_output=0;
274        d->stat_notplayed=0;
275        d->stat_minimumbuffer=WINSND_MINIMUMBUFFER;
276}
277
278static void winsnd_uninit(MSFilter *f){
279        WinSnd *d=(WinSnd*)f->data;
280        flushq(&d->rq,0);
281        flushq(&d->write_rq,0);
282#ifndef DISABLE_SPEEX
283        if (d->pst!=NULL)
284            speex_preprocess_state_destroy(d->pst);
285        d->pst=NULL;
286        d->pst_frame_size=0;
287#endif
288        d->ready=0;
289        d->workaround=0;
290        ms_mutex_destroy(&d->mutex);
291        ms_free(f->data);
292}
293
294static void add_input_buffer(WinSnd *d, WAVEHDR *hdr, int buflen){
295        mblk_t *m=allocb(buflen,0);
296        MMRESULT mr;
297        memset(hdr,0,sizeof(*hdr));
298        if (buflen==0) ms_error("add_input_buffer: buflen=0 !");
299        hdr->lpData=(LPSTR)m->b_wptr;
300        hdr->dwBufferLength=buflen;
301        hdr->dwFlags = 0;
302        hdr->dwUser = (DWORD)m;
303        mr = waveInPrepareHeader (d->indev,hdr,sizeof(*hdr));
304        if (mr != MMSYSERR_NOERROR){
305                ms_error("waveInPrepareHeader() error");
306                return ;
307        }
308        mr=waveInAddBuffer(d->indev,hdr,sizeof(*hdr));
309        if (mr != MMSYSERR_NOERROR){
310                ms_error("waveInAddBuffer() error");
311                return ;
312        }
313}
314
315static void CALLBACK
316read_callback (HWAVEIN waveindev, UINT uMsg, DWORD dwInstance, DWORD dwParam1,
317                DWORD dwParam2)
318{
319        WAVEHDR *wHdr=(WAVEHDR *) dwParam1;
320        MSFilter *f=(MSFilter *)dwInstance;
321        WinSnd *d=(WinSnd*)f->data;
322        mblk_t *m;
323        int bsize;
324        switch (uMsg){
325                case WIM_OPEN:
326                        ms_debug("read_callback : WIM_OPEN");
327                break;
328                case WIM_CLOSE:
329                        ms_debug("read_callback : WIM_CLOSE");
330                break;
331                case WIM_DATA:
332                        bsize=wHdr->dwBytesRecorded;
333                        if (bsize<=0) {
334#if 0
335                                if (d->running==TRUE) /* avoid adding buffer back when calling waveInReset */
336                                {
337                                        MMRESULT mr;
338                                        mr=waveInAddBuffer(d->indev,wHdr,sizeof(*wHdr));
339                                        if (mr != MMSYSERR_NOERROR){
340                                                ms_error("waveInAddBuffer() error");
341                                                return ;
342                                        }
343                                        ms_warning("read_callback : EMPTY DATA, WIM_DATA (%p,%i)",wHdr,bsize);
344                                }
345                                m=(mblk_t*)wHdr->dwUser;
346                                wHdr->dwUser=0;
347                                freemsg(m);
348                                return;
349#endif
350                        }
351
352                        /* ms_warning("read_callback : WIM_DATA (%p,%i)",wHdr,bsize); */
353                        m=(mblk_t*)wHdr->dwUser;
354                        m->b_wptr+=bsize;
355                        wHdr->dwUser=0;
356                        ms_mutex_lock(&d->mutex);
357                        putq(&d->rq,m);
358                        ms_mutex_unlock(&d->mutex);
359                        d->bytes_read+=wHdr->dwBufferLength;
360                        d->stat_input++;
361                        d->stat_input++;
362#ifdef WIN32_TIMERS
363                        if (f->ticker->TimeEvent!=NULL)
364                                SetEvent(f->ticker->TimeEvent);
365#endif
366                break;
367        }
368}
369
370
371static void winsnd_read_preprocess(MSFilter *f){
372        WinSnd *d=(WinSnd*)f->data;
373        MMRESULT mr;
374        int i;
375        int bsize;
376        DWORD dwFlag;
377
378        d->stat_input=0;
379        d->stat_output=0;
380        d->stat_notplayed=0;
381        d->stat_minimumbuffer=WINSND_MINIMUMBUFFER;
382
383        winsnd_apply_settings(d);
384        /* Init Microphone device */
385        dwFlag = CALLBACK_FUNCTION;
386        if (d->dev_id != WAVE_MAPPER)
387                dwFlag = WAVE_MAPPED | CALLBACK_FUNCTION;
388        mr = waveInOpen (&d->indev, d->dev_id, &d->wfx,
389                    (DWORD) read_callback, (DWORD)f, dwFlag);
390        if (mr != MMSYSERR_NOERROR)
391        {
392            ms_error("Failed to prepare windows sound device. (waveInOpen:0x%i)", mr);
393                mr = waveInOpen (&d->indev, WAVE_MAPPER, &d->wfx,
394                                        (DWORD) read_callback, (DWORD)d, CALLBACK_FUNCTION);
395                if (mr != MMSYSERR_NOERROR)
396                {
397                        d->indev=NULL;
398                        ms_error("Failed to prepare windows sound device. (waveInOpen:0x%i)", mr);
399                    return ;
400                }
401        }
402        bsize=WINSND_NSAMPLES*d->wfx.nAvgBytesPerSec/8000;
403        ms_debug("Using input buffers of %i bytes",bsize);
404        for(i=0;i<WINSND_NBUFS;++i){
405                WAVEHDR *hdr=&d->hdrs_read[i];
406                add_input_buffer(d,hdr,bsize);
407        }
408        d->running=TRUE;
409        mr=waveInStart(d->indev);
410        if (mr != MMSYSERR_NOERROR){
411                ms_error("waveInStart() error");
412                return ;
413        }
414#ifndef _TRUE_TIME
415        ms_ticker_set_time_func(f->ticker,winsnd_get_cur_time,d);
416#endif
417}
418
419static void winsnd_read_postprocess(MSFilter *f){
420        WinSnd *d=(WinSnd*)f->data;
421        MMRESULT mr;
422        int i;
423#ifndef _TRUE_TIME
424        ms_ticker_set_time_func(f->ticker,NULL,NULL);
425#endif
426        d->running=FALSE;
427        mr=waveInStop(d->indev);
428        if (mr != MMSYSERR_NOERROR){
429                ms_error("waveInStop() error");
430                return ;
431        }
432        mr=waveInReset(d->indev);
433        if (mr != MMSYSERR_NOERROR){
434                ms_error("waveInReset() error");
435                return ;
436        }
437        for(i=0;i<WINSND_NBUFS;++i){
438                WAVEHDR *hdr=&d->hdrs_read[i];
439                if (hdr->dwFlags & WHDR_PREPARED)
440                {
441                        mr = waveInUnprepareHeader(d->indev,hdr,sizeof (*hdr));
442                        if (mr != MMSYSERR_NOERROR){
443                                ms_error("waveInUnPrepareHeader() error");
444                        }
445                }
446        }
447        mr = waveInClose(d->indev);
448        if (mr != MMSYSERR_NOERROR){
449                ms_error("waveInClose() error");
450                return ;
451        }
452
453        ms_message("Shutting down sound device (playing: %i) (input-output: %i) (notplayed: %i)", d->nbufs_playing, d->stat_input - d->stat_output, d->stat_notplayed);
454        flushq(&d->rq,0);
455}
456
457static void winsnd_read_process(MSFilter *f){
458        WinSnd *d=(WinSnd*)f->data;
459        mblk_t *m;
460        int i;
461        ms_mutex_lock(&d->mutex);
462        while((m=getq(&d->rq))!=NULL){
463                ms_queue_put(f->outputs[0],m);
464        }
465        ms_mutex_unlock(&d->mutex);
466        for(i=0;i<WINSND_NBUFS;++i){
467                WAVEHDR *hdr=&d->hdrs_read[i];
468                if (hdr->dwUser==0) {
469                        MMRESULT mr;
470                        mr=waveInUnprepareHeader(d->indev,hdr,sizeof(*hdr));
471                        if (mr!=MMSYSERR_NOERROR)
472                                ms_warning("winsnd_read_process: Fail to unprepare header!");
473                        add_input_buffer(d,hdr,hdr->dwBufferLength);
474                }
475        }
476}
477
478static void CALLBACK
479write_callback(HWAVEOUT outdev, UINT uMsg, DWORD dwInstance,
480                 DWORD dwParam1, DWORD dwParam2)
481{
482        WAVEHDR *hdr=(WAVEHDR *) dwParam1;
483        WinSnd *d=(WinSnd*)dwInstance;
484       
485        switch (uMsg){
486                case WOM_OPEN:
487                        break;
488                case WOM_CLOSE:
489                case WOM_DONE:
490                        if (hdr){
491                                d->nbufs_playing--;
492                        }
493                        if (d->stat_output==0)
494                        {
495                                d->stat_input=1; /* reset */
496                                d->stat_notplayed=0;
497                        }
498                        d->stat_output++;
499                break;
500        }
501}
502
503static void winsnd_write_preprocess(MSFilter *f){
504        WinSnd *d=(WinSnd*)f->data;
505        MMRESULT mr;
506        DWORD dwFlag;
507        int i;
508
509        d->stat_input=0;
510        d->stat_output=0;
511        d->stat_notplayed=0;
512        d->stat_minimumbuffer=WINSND_MINIMUMBUFFER;
513
514        winsnd_apply_settings(d);
515        /* Init Microphone device */
516        dwFlag = CALLBACK_FUNCTION;
517        if (d->dev_id != WAVE_MAPPER)
518                dwFlag = WAVE_MAPPED | CALLBACK_FUNCTION;
519        mr = waveOutOpen (&d->outdev, d->dev_id, &d->wfx,
520                    (DWORD) write_callback, (DWORD)d, dwFlag);
521        if (mr != MMSYSERR_NOERROR)
522        {
523                ms_error("Failed to open windows sound device %i. (waveOutOpen:0x%i)",d->dev_id, mr);
524                mr = waveOutOpen (&d->outdev, WAVE_MAPPER, &d->wfx,
525                                        (DWORD) write_callback, (DWORD)d, CALLBACK_FUNCTION);
526                if (mr != MMSYSERR_NOERROR)
527                {
528                        ms_error("Failed to open windows sound device %i. (waveOutOpen:0x%i)",d->dev_id, mr);
529                        d->outdev=NULL;
530                        return ;
531                }
532        }
533        for(i=0;i<WINSND_OUT_NBUFS;++i){
534                WAVEHDR *hdr=&d->hdrs_write[i];
535                hdr->dwFlags=0;
536                hdr->dwUser=0;
537        }
538}
539
540static void winsnd_write_postprocess(MSFilter *f){
541        WinSnd *d=(WinSnd*)f->data;
542        MMRESULT mr;
543        int i;
544        if (d->outdev==NULL) return;
545        mr=waveOutReset(d->outdev);
546        if (mr != MMSYSERR_NOERROR){
547                ms_error("waveOutReset() error");
548                return ;
549        }
550        for(i=0;i<WINSND_OUT_NBUFS;++i){
551                WAVEHDR *hdr=&d->hdrs_write[i];
552                mblk_t *old;
553                if (hdr->dwFlags & WHDR_DONE){
554                        mr=waveOutUnprepareHeader(d->outdev,hdr,sizeof(*hdr));
555                        if (mr != MMSYSERR_NOERROR){
556                                ms_error("waveOutUnprepareHeader error");
557                        }
558                        old=(mblk_t*)hdr->dwUser;
559                        if (old) freemsg(old);
560                        hdr->dwUser=0;
561                }
562        }
563        mr=waveOutClose(d->outdev);
564        if (mr != MMSYSERR_NOERROR){
565                ms_error("waveOutClose() error");
566                return ;
567        }
568        ms_message("Shutting down sound device (playing: %i) (d->write_rq.q_mcount=%i) (input-output: %i) (notplayed: %i)", d->nbufs_playing, d->write_rq.q_mcount, d->stat_input - d->stat_output, d->stat_notplayed);
569        flushq(&d->write_rq,0);
570        d->ready=0;
571        d->workaround=0;
572
573#ifndef DISABLE_SPEEX
574        if (d->pst!=NULL)
575            speex_preprocess_state_destroy(d->pst);
576        d->pst=NULL;
577        d->pst_frame_size=0;
578#endif
579}
580
581static void winsnd_write_process(MSFilter *f){
582        WinSnd *d=(WinSnd*)f->data;
583        mblk_t *m,*old;
584        MMRESULT mr;
585        int i;
586        int discarded=0;
587        int possible_size=0;
588
589        if (d->outdev==NULL) {
590                ms_queue_flush(f->inputs[0]);
591                return;
592        }
593
594        while((m=ms_queue_get(f->inputs[0]))!=NULL){
595                possible_size = msgdsize(m);
596#ifndef DISABLE_SPEEX
597                if (d->pst_frame_size==0)
598                {
599                        d->pst_frame_size=possible_size;
600
601                        d->pst = speex_preprocess_state_init(d->pst_frame_size/2, d->wfx.nSamplesPerSec);
602                        if (d->pst!=NULL) {
603                                float f;
604                                i=1;
605                                speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_VAD, &i);
606                                i=0;
607                                speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_DENOISE, &i);
608                                i=0;
609                                speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_AGC, &i);
610                                f=8000;
611                                speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_AGC_LEVEL, &f);
612                                i=0;
613                                speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_DEREVERB, &i);
614                        }
615                }
616#endif
617
618                putq(&d->write_rq,m);
619        }
620
621#ifdef AMD_HACK
622        /* too many sound card are crappy on windows... */
623        d->stat_minimumbuffer=15;
624  if (d->wfx.nSamplesPerSec>=32000) /* better results for high rates */
625        d->stat_minimumbuffer=8;
626#endif
627
628  if (d->wfx.nSamplesPerSec>=32000) /* better results for high rates */
629  {
630          if (d->nbufs_playing+d->write_rq.q_mcount<4)
631          {
632                  d->ready=0;
633          }
634  }
635  else
636  {
637          if (d->nbufs_playing+d->write_rq.q_mcount<7)
638          {
639                  d->ready=0;
640          }
641  }
642#if defined(WCE_OPTICON_WORKAROUND)
643        if (d->workaround==0)
644        {
645                d->workaround=1;
646                Sleep(WCE_OPTICON_WORKAROUND);
647        }
648#endif
649
650        while((m=peekq(&d->write_rq))!=NULL){
651
652#ifndef DISABLE_SPEEX
653                int vad=1;
654                if (d->pst!=NULL && msgdsize(m)==d->pst_frame_size && d->pst_frame_size<=4096)
655                {
656                        char tmp[4096];
657                        memcpy(tmp, m->b_rptr, msgdsize(m));
658                        vad = speex_preprocess(d->pst, (short*)tmp, NULL);
659
660                        if (d->ready==0)
661                        {
662                                if (vad==0)
663                                {
664                                        int missing;
665          missing = 10 - d->write_rq.q_mcount - d->nbufs_playing;
666          if (d->wfx.nSamplesPerSec>=32000) /* better results for high rates */
667            missing = 6 - d->write_rq.q_mcount - d->nbufs_playing;
668
669                      ms_message("WINSND trouble: inserting %i silence", missing);
670                                        while(missing>0)
671                                        {
672                                                old=dupb(m);
673                                                putq(&d->write_rq,old);
674                                                missing--;
675                                        }
676                                }
677                                d->ready=1;
678                        }
679                }
680#else
681                if (d->ready==0)
682                {
683      int missing;
684                        missing = 10 - d->write_rq.q_mcount - d->nbufs_playing;
685      if (d->wfx.nSamplesPerSec>=32000) /* better results for high rates */
686                        missing = 6 - d->write_rq.q_mcount - d->nbufs_playing;
687                        ms_message("WINSND trouble: inserting %i silence", missing);
688                        while(missing>0)
689                        {
690                                old=dupb(m);
691                                putq(&d->write_rq,old);
692                                missing--;
693                        }
694                        d->ready=1;
695                }
696#endif
697
698                for(i=0;i<d->stat_minimumbuffer;++i){
699                        WAVEHDR *hdr=&d->hdrs_write[i];
700                        if (hdr->dwFlags & WHDR_DONE){
701                                old=(mblk_t*)hdr->dwUser;
702                                mr=waveOutUnprepareHeader(d->outdev,hdr,sizeof(*hdr));
703                                if (mr != MMSYSERR_NOERROR){
704                                        ms_error("waveOutUnprepareHeader error");
705                                }
706                                freemsg(old);
707                                hdr->dwUser=0;
708                        }
709                        if (hdr->dwUser==0){
710                                hdr->lpData=(LPSTR)m->b_rptr;
711                                hdr->dwBufferLength=msgdsize(m);
712                                hdr->dwFlags = 0;
713                            hdr->dwUser = (DWORD)m;
714                            mr = waveOutPrepareHeader(d->outdev,hdr,sizeof(*hdr));
715                            if (mr != MMSYSERR_NOERROR){
716                                        ms_error("waveOutPrepareHeader() error");
717                                        getq(&d->write_rq);
718                                        freemsg(m);
719                                        discarded++;
720                                        d->stat_notplayed++;
721                                        break;
722                                }
723                                mr=waveOutWrite(d->outdev,hdr,sizeof(*hdr));
724                                if (mr != MMSYSERR_NOERROR){
725                                        ms_error("waveOutWrite() error");
726                                        getq(&d->write_rq);
727                                        freemsg(m);
728                                        discarded++;
729                                        d->stat_notplayed++;
730                                        break;
731                                }else {
732                                        getq(&d->write_rq);
733                                        d->nbufs_playing++;
734                                        /* ms_debug("waveOutWrite() done"); */
735                                }
736                                break;
737                        }
738                }
739                if (i==d->stat_minimumbuffer){
740                        //ms_error("winsnd_write_process: All buffers are busy.");
741#ifndef DISABLE_SPEEX
742                        if (d->pst==NULL)
743                        {
744                                /* initial behavior (detection in process?) */
745                                getq(&d->write_rq);
746                                freemsg(m);
747                    discarded++;
748                    d->stat_notplayed++;
749                        }
750                        else
751                        {
752                                if (vad==0)
753                                {
754                                        getq(&d->write_rq);
755                                        freemsg(m);
756          ms_message("WINSND trouble: silence removed");
757                            discarded++;
758                            d->stat_notplayed++;
759                                }
760                        }
761#else
762                        getq(&d->write_rq);
763                        freemsg(m);
764                        discarded++;
765                        d->stat_notplayed++;
766#endif
767
768                        break;
769                }
770        }
771}
772
773static int set_rate(MSFilter *f, void *arg){
774        WinSnd *d=(WinSnd*)f->data;
775        d->wfx.nSamplesPerSec=*((int*)arg);
776        return 0;
777}
778
779static int set_nchannels(MSFilter *f, void *arg){
780        WinSnd *d=(WinSnd*)f->data;
781        d->wfx.nChannels=*((int*)arg);
782        return 0;
783}
784
785static int winsnd_get_stat_input(MSFilter *f, void *arg){
786        WinSnd *d=(WinSnd*)f->data;
787        return d->stat_input;
788}
789
790static int winsnd_get_stat_ouptut(MSFilter *f, void *arg){
791        WinSnd *d=(WinSnd*)f->data;
792
793        return d->stat_output;
794}
795
796static int winsnd_get_stat_discarded(MSFilter *f, void *arg){
797        WinSnd *d=(WinSnd*)f->data;
798
799        return d->stat_notplayed;
800}
801
802static MSFilterMethod winsnd_methods[]={
803        {       MS_FILTER_SET_SAMPLE_RATE       , set_rate      },
804        {       MS_FILTER_SET_NCHANNELS         , set_nchannels },
805        {       MS_FILTER_GET_STAT_INPUT, winsnd_get_stat_input },
806        {       MS_FILTER_GET_STAT_OUTPUT, winsnd_get_stat_ouptut },
807        {       MS_FILTER_GET_STAT_DISCARDED, winsnd_get_stat_discarded },
808        {       0                               , NULL          }
809};
810
811MSFilterDesc winsnd_read_desc={
812        MS_WINSND_READ_ID,
813        "MSWinSndRead",
814        "Sound capture filter for Windows Sound drivers",
815        MS_FILTER_OTHER,
816        NULL,
817    0,
818        1,
819        winsnd_init,
820    winsnd_read_preprocess,
821        winsnd_read_process,
822        winsnd_read_postprocess,
823    winsnd_uninit,
824        winsnd_methods
825};
826
827
828MSFilterDesc winsnd_write_desc={
829        MS_WINSND_WRITE_ID,
830        "MSWinSndWrite",
831        "Sound playback filter for Windows Sound drivers",
832        MS_FILTER_OTHER,
833        NULL,
834    1,
835        0,
836        winsnd_init,
837    winsnd_write_preprocess,
838        winsnd_write_process,
839        winsnd_write_postprocess,
840        winsnd_uninit,
841    winsnd_methods
842};
843
844MSFilter *ms_winsnd_read_new(MSSndCard *card){
845        MSFilter *f=ms_filter_new_from_desc(&winsnd_read_desc);
846        WinSndCard *wc=(WinSndCard*)card->data;
847        WinSnd *d=(WinSnd*)f->data;
848        d->dev_id=wc->in_devid;
849        return f;
850}
851
852
853MSFilter *ms_winsnd_write_new(MSSndCard *card){
854        MSFilter *f=ms_filter_new_from_desc(&winsnd_write_desc);
855        WinSndCard *wc=(WinSndCard*)card->data;
856        WinSnd *d=(WinSnd*)f->data;
857        d->dev_id=wc->out_devid;
858        return f;
859}
860
861MS_FILTER_DESC_EXPORT(winsnd_read_desc)
862MS_FILTER_DESC_EXPORT(winsnd_write_desc)
Note: See TracBrowser for help on using the repository browser.