]> sjero.net Git - linphone/blob - linphone/mediastreamer2/src/winsnd3.c
a554a159fc3e23f1cb8b66ac30db726a4b6d3625
[linphone] / linphone / mediastreamer2 / src / winsnd3.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 "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
35
36 #define WINSND_NBUFS 10
37 #define WINSND_OUT_DELAY 0.100
38 #define WINSND_OUT_NBUFS 20
39 #define WINSND_NSAMPLES 320
40 #define WINSND_MINIMUMBUFFER 5
41
42 static MSFilter *ms_winsnd_read_new(MSSndCard *card);
43 static MSFilter *ms_winsnd_write_new(MSSndCard *card);
44
45 typedef struct WinSndCard{
46         int in_devid;
47         int out_devid;
48 }WinSndCard;
49
50 static void winsndcard_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent){
51     MMRESULT mr = MMSYSERR_NOERROR;
52     DWORD dwVolume = 0xFFFF;
53     dwVolume = ((0xFFFF) * percent) / 100;
54
55         switch(e){
56                 case MS_SND_CARD_MASTER:
57             /*mr = waveOutSetVolume(d->waveoutdev, dwVolume); */
58                 if (mr != MMSYSERR_NOERROR)
59                 {
60                 ms_warning("Failed to set master volume. (waveOutSetVolume:0x%i)", mr);
61                 return;
62                 }
63         break;
64         case MS_SND_CARD_CAPTURE:
65                 break;
66                 case MS_SND_CARD_PLAYBACK:
67                 break;
68         default:
69                         ms_warning("winsnd_card_set_level: unsupported command.");
70         }
71 }
72
73 static int winsndcard_get_level(MSSndCard *card, MSSndCardMixerElem e){
74         switch(e){
75                 case MS_SND_CARD_MASTER:
76             /*mr=waveOutGetVolume(d->waveoutdev, &dwVolume);*/
77             /* Transform to 0 to 100 scale*/
78             /*dwVolume = (dwVolume *100) / (0xFFFF);*/
79             return 60;
80         break;
81         case MS_SND_CARD_CAPTURE:
82                 break;
83                 case MS_SND_CARD_PLAYBACK:
84                 break;
85                 default:
86                         ms_warning("winsnd_card_get_level: unsupported command.");
87                         return -1;
88         }
89         return -1;
90 }
91
92 static void winsndcard_set_source(MSSndCard *card, MSSndCardCapture source){
93
94         switch(source){
95                 case MS_SND_CARD_MIC:
96                 break;
97                 case MS_SND_CARD_LINE:
98                 break;
99         }       
100 }
101
102 static void winsndcard_init(MSSndCard *card){
103         WinSndCard *c=(WinSndCard *)ms_new(WinSndCard,1);
104         card->data=c;
105 }
106
107 static void winsndcard_uninit(MSSndCard *card){
108         ms_free(card->data);
109 }
110
111 static void winsndcard_detect(MSSndCardManager *m);
112 static  MSSndCard *winsndcard_dup(MSSndCard *obj);
113
114 MSSndCardDesc winsnd_card_desc={
115         "WINSND",
116         winsndcard_detect,
117         winsndcard_init,
118         winsndcard_set_level,
119         winsndcard_get_level,
120         winsndcard_set_source,
121         NULL,
122         NULL,
123         ms_winsnd_read_new,
124         ms_winsnd_write_new,
125         winsndcard_uninit,
126         winsndcard_dup
127 };
128
129 static  MSSndCard *winsndcard_dup(MSSndCard *obj){
130         MSSndCard *card=ms_snd_card_new(&winsnd_card_desc);
131         card->name=ms_strdup(obj->name);
132         card->data=ms_new(WinSndCard,1);
133         memcpy(card->data,obj->data,sizeof(WinSndCard));
134         return card;
135 }
136
137 static MSSndCard *winsndcard_new(const char *name, int in_dev, int out_dev, unsigned cap){
138         MSSndCard *card=ms_snd_card_new(&winsnd_card_desc);
139         WinSndCard *d=(WinSndCard*)card->data;
140         card->name=ms_strdup(name);
141         d->in_devid=in_dev;
142         d->out_devid=out_dev;
143         card->capabilities=cap;
144         return card;
145 }
146
147 static void add_or_update_card(MSSndCardManager *m, const char *name, int indev, int outdev, unsigned int capability){
148         MSSndCard *card;
149         const MSList *elem=ms_snd_card_manager_get_list(m);
150         for(;elem!=NULL;elem=elem->next){
151                 card=(MSSndCard*)elem->data;
152                 if (strcmp(card->name,name)==0){
153                         /*update already entered card */
154                         WinSndCard *d=(WinSndCard*)card->data;
155                         card->capabilities|=capability;
156                         if (indev!=-1) 
157                                 d->in_devid=indev;
158                         if (outdev!=-1)
159                                 d->out_devid=outdev;
160                                 
161                         return;
162                 }
163         }
164         /* add this new card:*/
165         ms_snd_card_manager_add_card(m,winsndcard_new(name,indev,outdev,capability));
166 }
167
168 static void winsndcard_detect(MSSndCardManager *m){
169     MMRESULT mr = NOERROR;
170     unsigned int nOutDevices = waveOutGetNumDevs ();
171     unsigned int nInDevices = waveInGetNumDevs ();
172     unsigned int item;
173
174     if (nOutDevices>nInDevices)
175                 nInDevices = nOutDevices;
176
177     for (item = 0; item < nInDevices; item++){
178                 
179         WAVEINCAPS incaps;
180         WAVEOUTCAPS outcaps;
181         mr = waveInGetDevCaps (item, &incaps, sizeof (WAVEINCAPS));
182         if (mr == MMSYSERR_NOERROR)
183                 {
184 #if defined(_WIN32_WCE)
185                         char card[256];
186                         snprintf(card, sizeof(card), "Input card %i", item);
187                         add_or_update_card(m,card,item,-1,MS_SND_CARD_CAP_CAPTURE);
188                         /* _tprintf(L"new card: %s", incaps.szPname); */
189 #else
190                         add_or_update_card(m,incaps.szPname,item,-1,MS_SND_CARD_CAP_CAPTURE);
191 #endif
192                 }
193         mr = waveOutGetDevCaps (item, &outcaps, sizeof (WAVEOUTCAPS));
194         if (mr == MMSYSERR_NOERROR)
195                 {
196 #if defined(_WIN32_WCE)
197                         char card[256];
198                         snprintf(card, sizeof(card), "Output card %i", item);
199                 add_or_update_card(m,card,-1,item,MS_SND_CARD_CAP_PLAYBACK);
200                         /* _tprintf(L"new card: %s", outcaps.szPname); */
201 #else
202                 add_or_update_card(m,outcaps.szPname,-1,item,MS_SND_CARD_CAP_PLAYBACK);
203 #endif
204                 }
205     }
206 }
207
208
209 typedef struct WinSnd{
210         int dev_id;
211         HWAVEIN indev;
212         HWAVEOUT outdev;
213         WAVEFORMATEX wfx;
214         WAVEHDR hdrs_read[WINSND_NBUFS];
215         WAVEHDR hdrs_write[WINSND_OUT_NBUFS];
216         queue_t rq;
217         ms_mutex_t mutex;
218         unsigned int bytes_read;
219         unsigned int nbufs_playing;
220         bool_t running;
221         int outcurbuf;
222         int nsamples;
223         queue_t wq;
224         int32_t stat_input;
225         int32_t stat_output;
226         int32_t stat_notplayed;
227
228         int32_t stat_minimumbuffer;
229         int ready;
230         int workaround; /* workaround for opticon audio device */
231         bool_t overrun;
232 }WinSnd;
233
234 static void winsnd_apply_settings(WinSnd *d){
235         d->wfx.nBlockAlign=d->wfx.nChannels*d->wfx.wBitsPerSample/8;
236         d->wfx.nAvgBytesPerSec=d->wfx.nSamplesPerSec*d->wfx.nBlockAlign;
237 }
238
239
240 #ifndef _TRUE_TIME
241 static uint64_t winsnd_get_cur_time( void *data){
242         WinSnd *d=(WinSnd*)data;
243         uint64_t curtime=((uint64_t)d->bytes_read*1000)/(uint64_t)d->wfx.nAvgBytesPerSec;
244         /* ms_debug("winsnd_get_cur_time: bytes_read=%u return %lu\n",d->bytes_read,(unsigned long)curtime); */
245         return curtime;
246 }
247 #endif
248
249
250 static void winsnd_init(MSFilter *f){
251         WinSnd *d=(WinSnd *)ms_new0(WinSnd,1);
252         d->wfx.wFormatTag = WAVE_FORMAT_PCM;
253         d->wfx.cbSize = 0;
254         d->wfx.nAvgBytesPerSec = 16000;
255         d->wfx.nBlockAlign = 2;
256         d->wfx.nChannels = 1;
257         d->wfx.nSamplesPerSec = 8000;
258         d->wfx.wBitsPerSample = 16;
259         qinit(&d->rq);
260         qinit(&d->wq);
261         d->ready=0;
262         d->workaround=0;
263         ms_mutex_init(&d->mutex,NULL);
264         f->data=d;
265
266         d->stat_input=0;
267         d->stat_output=0;
268         d->stat_notplayed=0;
269         d->stat_minimumbuffer=WINSND_MINIMUMBUFFER;
270 }
271
272 static void winsnd_uninit(MSFilter *f){
273         WinSnd *d=(WinSnd*)f->data;
274         flushq(&d->rq,0);
275         flushq(&d->wq,0);
276         d->ready=0;
277         d->workaround=0;
278         ms_mutex_destroy(&d->mutex);
279         ms_free(f->data);
280 }
281
282 static void add_input_buffer(WinSnd *d, WAVEHDR *hdr, int buflen){
283         mblk_t *m=allocb(buflen,0);
284         MMRESULT mr;
285         memset(hdr,0,sizeof(*hdr));
286         if (buflen==0) ms_error("add_input_buffer: buflen=0 !");
287         hdr->lpData=(LPSTR)m->b_wptr;
288         hdr->dwBufferLength=buflen;
289         hdr->dwFlags = 0;
290         hdr->dwUser = (DWORD)m;
291         mr = waveInPrepareHeader (d->indev,hdr,sizeof(*hdr));
292         if (mr != MMSYSERR_NOERROR){
293                 ms_error("waveInPrepareHeader() error");
294                 return ;
295         }
296         mr=waveInAddBuffer(d->indev,hdr,sizeof(*hdr));
297         if (mr != MMSYSERR_NOERROR){
298                 ms_error("waveInAddBuffer() error");
299                 return ;
300         }
301 }
302
303 static void CALLBACK 
304 read_callback (HWAVEIN waveindev, UINT uMsg, DWORD dwInstance, DWORD dwParam1,
305                 DWORD dwParam2)
306 {
307         WAVEHDR *wHdr=(WAVEHDR *) dwParam1;
308         MSFilter *f=(MSFilter *)dwInstance;
309         WinSnd *d=(WinSnd*)f->data;
310         mblk_t *m;
311         int bsize;
312         switch (uMsg){
313                 case WIM_OPEN:
314                         ms_debug("read_callback : WIM_OPEN");
315                 break;
316                 case WIM_CLOSE:
317                         ms_debug("read_callback : WIM_CLOSE");
318                 break;
319                 case WIM_DATA:
320                         bsize=wHdr->dwBytesRecorded;
321
322                         /* ms_warning("read_callback : WIM_DATA (%p,%i)",wHdr,bsize); */
323                         m=(mblk_t*)wHdr->dwUser;
324                         m->b_wptr+=bsize;
325                         wHdr->dwUser=0;
326                         ms_mutex_lock(&d->mutex);
327                         putq(&d->rq,m);
328                         ms_mutex_unlock(&d->mutex);
329                         d->bytes_read+=wHdr->dwBufferLength;
330                         d->stat_input++;
331                         d->stat_input++;
332 #ifdef WIN32_TIMERS
333                         if (f->ticker->TimeEvent!=NULL)
334                                 SetEvent(f->ticker->TimeEvent);
335 #endif
336                 break;
337         }
338 }
339
340
341 static void winsnd_read_preprocess(MSFilter *f){
342         WinSnd *d=(WinSnd*)f->data;
343         MMRESULT mr;
344         int i;
345         int bsize;
346         DWORD dwFlag;
347
348         d->stat_input=0;
349         d->stat_output=0;
350         d->stat_notplayed=0;
351         d->stat_minimumbuffer=WINSND_MINIMUMBUFFER;
352
353         winsnd_apply_settings(d);
354         /* Init Microphone device */
355         dwFlag = CALLBACK_FUNCTION;
356         if (d->dev_id != WAVE_MAPPER)
357                 dwFlag = WAVE_MAPPED | CALLBACK_FUNCTION;
358         mr = waveInOpen (&d->indev, d->dev_id, &d->wfx,
359                     (DWORD) read_callback, (DWORD)f, dwFlag);
360         if (mr != MMSYSERR_NOERROR)
361         {
362             ms_error("Failed to prepare windows sound device. (waveInOpen:0x%i)", mr);
363                 mr = waveInOpen (&d->indev, WAVE_MAPPER, &d->wfx,
364                                         (DWORD) read_callback, (DWORD)f, CALLBACK_FUNCTION);
365                 if (mr != MMSYSERR_NOERROR)
366                 {
367                         d->indev=NULL;
368                         ms_error("Failed to prepare windows sound device. (waveInOpen:0x%i)", mr);
369                     return ;
370                 }
371         }
372         bsize=WINSND_NSAMPLES*d->wfx.nAvgBytesPerSec/8000;
373         ms_debug("Using input buffers of %i bytes",bsize);
374         for(i=0;i<WINSND_NBUFS;++i){
375                 WAVEHDR *hdr=&d->hdrs_read[i];
376                 add_input_buffer(d,hdr,bsize);
377         }
378         d->running=TRUE;
379         mr=waveInStart(d->indev);
380         if (mr != MMSYSERR_NOERROR){
381                 ms_error("waveInStart() error");
382                 return ;
383         }
384 #ifndef _TRUE_TIME
385         ms_ticker_set_time_func(f->ticker,winsnd_get_cur_time,d);
386 #endif
387 }
388
389 static void winsnd_read_postprocess(MSFilter *f){
390         WinSnd *d=(WinSnd*)f->data;
391         MMRESULT mr;
392         int i;
393 #ifndef _TRUE_TIME
394         ms_ticker_set_time_func(f->ticker,NULL,NULL);
395 #endif
396         d->running=FALSE;
397         mr=waveInStop(d->indev);
398         if (mr != MMSYSERR_NOERROR){
399                 ms_error("waveInStop() error");
400                 return ;
401         }
402         mr=waveInReset(d->indev);
403         if (mr != MMSYSERR_NOERROR){
404                 ms_error("waveInReset() error");
405                 return ;
406         }
407         for(i=0;i<WINSND_NBUFS;++i){
408                 WAVEHDR *hdr=&d->hdrs_read[i];
409                 if (hdr->dwFlags & WHDR_PREPARED)
410                 {
411                         mr = waveInUnprepareHeader(d->indev,hdr,sizeof (*hdr));
412                         if (mr != MMSYSERR_NOERROR){
413                                 ms_error("waveInUnPrepareHeader() error");
414                         }
415                 }
416         }
417         mr = waveInClose(d->indev);
418         if (mr != MMSYSERR_NOERROR){
419                 ms_error("waveInClose() error");
420                 return ;
421         }
422
423         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);
424         flushq(&d->rq,0);
425 }
426
427 static void winsnd_read_process(MSFilter *f){
428         WinSnd *d=(WinSnd*)f->data;
429         mblk_t *m;
430         int i;
431         ms_mutex_lock(&d->mutex);
432         while((m=getq(&d->rq))!=NULL){
433                 ms_queue_put(f->outputs[0],m);
434         }
435         ms_mutex_unlock(&d->mutex);
436         for(i=0;i<WINSND_NBUFS;++i){
437                 WAVEHDR *hdr=&d->hdrs_read[i];
438                 if (hdr->dwUser==0) {
439                         MMRESULT mr;
440                         mr=waveInUnprepareHeader(d->indev,hdr,sizeof(*hdr));
441                         if (mr!=MMSYSERR_NOERROR)
442                                 ms_warning("winsnd_read_process: Fail to unprepare header!");
443                         add_input_buffer(d,hdr,hdr->dwBufferLength);
444                 }
445         }
446 }
447
448 static void CALLBACK
449 write_callback(HWAVEOUT outdev, UINT uMsg, DWORD dwInstance,
450                  DWORD dwParam1, DWORD dwParam2)
451 {
452         WAVEHDR *hdr=(WAVEHDR *) dwParam1;
453         WinSnd *d=(WinSnd*)dwInstance;
454         
455         switch (uMsg){
456                 case WOM_OPEN:
457                         break;
458                 case WOM_CLOSE:
459                 case WOM_DONE:
460                         if (hdr){
461                                 d->nbufs_playing--;
462                         }
463                         if (d->stat_output==0)
464                         {
465                                 d->stat_input=1; /* reset */
466                                 d->stat_notplayed=0;
467                         }
468                         d->stat_output++;
469                 break;
470         }
471 }
472
473 static void winsnd_write_preprocess(MSFilter *f){
474         WinSnd *d=(WinSnd*)f->data;
475         MMRESULT mr;
476         DWORD dwFlag;
477         int i;
478
479         d->stat_input=0;
480         d->stat_output=0;
481         d->stat_notplayed=0;
482         d->stat_minimumbuffer=WINSND_MINIMUMBUFFER;
483
484         winsnd_apply_settings(d);
485         /* Init Microphone device */
486         dwFlag = CALLBACK_FUNCTION;
487         if (d->dev_id != WAVE_MAPPER)
488                 dwFlag = WAVE_MAPPED | CALLBACK_FUNCTION;
489         mr = waveOutOpen (&d->outdev, d->dev_id, &d->wfx,
490                     (DWORD) write_callback, (DWORD)d, dwFlag);
491         if (mr != MMSYSERR_NOERROR)
492         {
493                 ms_error("Failed to open windows sound device %i. (waveOutOpen:0x%i)",d->dev_id, mr);
494                 mr = waveOutOpen (&d->outdev, WAVE_MAPPER, &d->wfx,
495                                         (DWORD) write_callback, (DWORD)d, CALLBACK_FUNCTION);
496                 if (mr != MMSYSERR_NOERROR)
497                 {
498                         ms_error("Failed to open windows sound device %i. (waveOutOpen:0x%i)",d->dev_id, mr);
499                         d->outdev=NULL;
500                         return ;
501                 }
502         }
503         for(i=0;i<WINSND_OUT_NBUFS;++i){
504                 WAVEHDR *hdr=&d->hdrs_write[i];
505                 hdr->dwFlags=0;
506                 hdr->dwUser=0;
507         }
508         d->outcurbuf=0;
509         d->overrun=FALSE;
510         d->nsamples=0;
511 }
512
513 static void winsnd_write_postprocess(MSFilter *f){
514         WinSnd *d=(WinSnd*)f->data;
515         MMRESULT mr;
516         int i;
517         if (d->outdev==NULL) return;
518         mr=waveOutReset(d->outdev);
519         if (mr != MMSYSERR_NOERROR){
520                 ms_error("waveOutReset() error");
521                 return ;
522         }
523         for(i=0;i<WINSND_OUT_NBUFS;++i){
524                 WAVEHDR *hdr=&d->hdrs_write[i];
525                 mblk_t *old;
526                 if (hdr->dwFlags & WHDR_DONE){
527                         mr=waveOutUnprepareHeader(d->outdev,hdr,sizeof(*hdr));
528                         if (mr != MMSYSERR_NOERROR){
529                                 ms_error("waveOutUnprepareHeader error");
530                         }
531                         old=(mblk_t*)hdr->dwUser;
532                         if (old) freemsg(old);
533                         hdr->dwUser=0;
534                 }
535         }
536         mr=waveOutClose(d->outdev);
537         if (mr != MMSYSERR_NOERROR){
538                 ms_error("waveOutClose() error");
539                 return ;
540         }
541         d->ready=0;
542         d->workaround=0;
543 }
544
545 static void playout_buf(WinSnd *d, WAVEHDR *hdr, mblk_t *m){
546         MMRESULT mr;
547         hdr->dwUser=(DWORD)m;
548         hdr->lpData=(LPSTR)m->b_rptr;
549         hdr->dwBufferLength=msgdsize(m);
550         hdr->dwFlags = 0;
551         mr = waveOutPrepareHeader(d->outdev,hdr,sizeof(*hdr));
552         if (mr != MMSYSERR_NOERROR){
553                 ms_error("waveOutPrepareHeader() error");
554                 d->stat_notplayed++;
555         }
556         mr=waveOutWrite(d->outdev,hdr,sizeof(*hdr));
557         if (mr != MMSYSERR_NOERROR){
558                 ms_error("waveOutWrite() error");
559                 d->stat_notplayed++;
560         }else {
561                 d->nbufs_playing++;
562         }
563 }
564
565 static void winsnd_write_process(MSFilter *f){
566         WinSnd *d=(WinSnd*)f->data;
567         mblk_t *m;
568         MMRESULT mr;
569         mblk_t *old;
570         if (d->outdev==NULL) {
571                 ms_queue_flush(f->inputs[0]);
572                 return;
573         }
574         if (d->overrun){
575                 ms_warning("nbufs_playing=%i",d->nbufs_playing);
576                 if (d->nbufs_playing>0){
577                         ms_queue_flush(f->inputs[0]);
578                         return;
579                 }
580                 else d->overrun=FALSE;
581         }
582         while(1){
583                 int outcurbuf=d->outcurbuf % WINSND_OUT_NBUFS;
584                 WAVEHDR *hdr=&d->hdrs_write[outcurbuf];
585                 old=(mblk_t*)hdr->dwUser;
586                 if (d->nsamples==0){
587                         int tmpsize=WINSND_OUT_DELAY*d->wfx.nAvgBytesPerSec;
588                         mblk_t *tmp=allocb(tmpsize,0);
589                         memset(tmp->b_wptr,0,tmpsize);
590                         tmp->b_wptr+=tmpsize;
591                         playout_buf(d,hdr,tmp);
592                         d->outcurbuf++;
593                         d->nsamples+=WINSND_OUT_DELAY*d->wfx.nSamplesPerSec;
594                         continue;
595                 }
596                 m=ms_queue_get(f->inputs[0]);
597                 if (!m) break;
598                 d->nsamples+=msgdsize(m)/d->wfx.nBlockAlign;
599                 /*if the output buffer has finished to play, unprepare it*/
600                 if (hdr->dwFlags & WHDR_DONE){
601                         mr=waveOutUnprepareHeader(d->outdev,hdr,sizeof(*hdr));
602                         if (mr != MMSYSERR_NOERROR){
603                                 ms_error("waveOutUnprepareHeader error");
604                         }
605                         freemsg(old);
606                         old=NULL;
607                         hdr->dwFlags=0;
608                         hdr->dwUser=0;
609                 }
610                 if (old==NULL){
611                         /* a free wavheader */
612                         playout_buf(d,hdr,m);
613                 }else{
614                         /* no more free wavheader, overrun !*/
615                         ms_warning("WINSND overrun, restarting");
616                         d->overrun=TRUE;
617                         d->nsamples=0;
618                         waveOutReset(d->outdev);
619                 }
620                 d->outcurbuf++;
621         }
622 }
623
624 static int set_rate(MSFilter *f, void *arg){
625         WinSnd *d=(WinSnd*)f->data;
626         d->wfx.nSamplesPerSec=*((int*)arg);
627         return 0;
628 }
629
630 static int set_nchannels(MSFilter *f, void *arg){
631         WinSnd *d=(WinSnd*)f->data;
632         d->wfx.nChannels=*((int*)arg);
633         return 0;
634 }
635
636 static int winsnd_get_stat_input(MSFilter *f, void *arg){
637         WinSnd *d=(WinSnd*)f->data;
638         return d->stat_input;
639 }
640
641 static int winsnd_get_stat_ouptut(MSFilter *f, void *arg){
642         WinSnd *d=(WinSnd*)f->data;
643
644         return d->stat_output;
645 }
646
647 static int winsnd_get_stat_discarded(MSFilter *f, void *arg){
648         WinSnd *d=(WinSnd*)f->data;
649
650         return d->stat_notplayed;
651 }
652
653 static MSFilterMethod winsnd_methods[]={
654         {       MS_FILTER_SET_SAMPLE_RATE       , set_rate      },
655         {       MS_FILTER_SET_NCHANNELS         , set_nchannels },
656         {       MS_FILTER_GET_STAT_INPUT, winsnd_get_stat_input },
657         {       MS_FILTER_GET_STAT_OUTPUT, winsnd_get_stat_ouptut },
658         {       MS_FILTER_GET_STAT_DISCARDED, winsnd_get_stat_discarded },
659         {       0                               , NULL          }
660 };
661
662 MSFilterDesc winsnd_read_desc={
663         MS_WINSND_READ_ID,
664         "MSWinSndRead",
665         "Sound capture filter for Windows Sound drivers",
666         MS_FILTER_OTHER,
667         NULL,
668     0,
669         1,
670         winsnd_init,
671     winsnd_read_preprocess,
672         winsnd_read_process,
673         winsnd_read_postprocess,
674     winsnd_uninit,
675         winsnd_methods
676 };
677
678
679 MSFilterDesc winsnd_write_desc={
680         MS_WINSND_WRITE_ID,
681         "MSWinSndWrite",
682         "Sound playback filter for Windows Sound drivers",
683         MS_FILTER_OTHER,
684         NULL,
685     1,
686         0,
687         winsnd_init,
688     winsnd_write_preprocess,
689         winsnd_write_process,
690         winsnd_write_postprocess,
691         winsnd_uninit,
692     winsnd_methods
693 };
694
695 MSFilter *ms_winsnd_read_new(MSSndCard *card){
696         MSFilter *f=ms_filter_new_from_desc(&winsnd_read_desc);
697         WinSndCard *wc=(WinSndCard*)card->data;
698         WinSnd *d=(WinSnd*)f->data;
699         d->dev_id=wc->in_devid;
700         return f;
701 }
702
703
704 MSFilter *ms_winsnd_write_new(MSSndCard *card){
705         MSFilter *f=ms_filter_new_from_desc(&winsnd_write_desc);
706         WinSndCard *wc=(WinSndCard*)card->data;
707         WinSnd *d=(WinSnd*)f->data;
708         d->dev_id=wc->out_devid;
709         return f;
710 }
711
712 MS_FILTER_DESC_EXPORT(winsnd_read_desc)
713 MS_FILTER_DESC_EXPORT(winsnd_write_desc)