]> sjero.net Git - linphone/blob - linphone/mediastreamer2/src/winsnd.c
74f21d6203b6118db869992a0aa1325b55777432
[linphone] / linphone / mediastreamer2 / src / winsnd.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 #if defined(_WIN32_WCE)
21 #define DISABLE_SPEEX
22 #endif
23
24 #ifndef WINSND_BUFLEN
25 #define WINSND_BUFLEN 320
26 #endif
27
28 #ifndef MAX_WAVEHDR
29 #define MAX_WAVEHDR 6
30 #endif
31
32 #ifndef DISABLE_SPEEX
33 #include <speex/speex_preprocess.h>
34 #endif
35
36 #include "mediastreamer2/mssndcard.h"
37 #include "mediastreamer2/msfilter.h"
38 #include "mediastreamer2/msticker.h"
39
40 #ifdef WIN32
41 #include <malloc.h> /* for alloca */
42 #endif
43
44 #include <mmsystem.h>
45 #ifdef _MSC_VER
46 #include <mmreg.h>
47 #endif
48 #include <msacm.h>
49
50 MSFilter *ms_winsnd_read_new(MSSndCard *card);
51 MSFilter *ms_winsnd_write_new(MSSndCard *card);
52
53 typedef struct WinSndData{
54         char *pcmdev;
55         char *mixdev;
56         int   devid;
57
58     int sound_err;
59     WAVEFORMATEX wfx;
60 #ifdef CONTROLVOLUME
61         DWORD dwOldVolume;
62 #endif
63         WAVEHDR waveouthdr[30];
64     char waveoutbuffer[30][3200];
65     HWAVEOUT waveoutdev;
66     int buffer_playing;
67         int pos_whdr;
68
69     WAVEHDR waveinhdr[30];
70     HWAVEIN waveindev;
71     char waveinbuffer[30][3200];
72
73     int rate;
74         int bits;
75         ms_thread_t thread;
76         ms_mutex_t mutex;
77         queue_t rq;
78         MSBufferizer * bufferizer;
79         bool_t read_started;
80         bool_t write_started;
81         bool_t stereo;
82
83 #ifndef DISABLE_SPEEX
84         SpeexPreprocessState *pst;
85 #endif
86
87         uint64_t bytes_read;
88         int32_t stat_input;
89         int32_t stat_output;
90         int32_t stat_notplayed;
91 } WinSndData;
92
93 static uint64_t winsnd_get_cur_time( void *data){
94         WinSndData *d=(WinSndData*)data;
95         uint64_t curtime=(d->bytes_read*1000)/(d->rate*(d->bits/8)*((d->stereo==FALSE) ? 1 : 2));
96         ms_debug("winsnd_get_cur_time: bytes_read=%lu, rate=%i, bits=%i, stereo=%i return %lu\n",
97         (unsigned long)d->bytes_read,d->rate,d->bits,d->stereo,(unsigned long)curtime);
98         return curtime;
99 }
100
101 static void CALLBACK
102 SpeakerCallback (HWAVEOUT _waveoutdev, UINT uMsg, DWORD dwInstance,
103                  DWORD dwParam1, DWORD dwParam2)
104 {
105   WAVEHDR *wHdr;
106   WinSndData *device;
107
108   switch (uMsg)
109     {
110       case WOM_OPEN:
111           ms_message("SpeakerCallback : WOM_OPEN");
112         break;
113       case WOM_CLOSE:
114           ms_message("SpeakerCallback : WOM_CLOSE");
115         break;
116       case WOM_DONE:
117         wHdr = (WAVEHDR *) dwParam1;
118         device = (WinSndData *)dwInstance;
119         device->buffer_playing--;
120                 if (device->stat_output==0)
121                 {
122                         device->stat_input=1; /* reset */
123                         device->stat_notplayed=0;
124                 }
125                 device->stat_output++;
126         break;
127       default:
128         break;
129     }
130 }
131
132 static void CALLBACK
133 WaveInCallback (HWAVEIN waveindev, UINT uMsg, DWORD dwInstance, DWORD dwParam1,
134                 DWORD dwParam2)
135 {
136   WAVEHDR *wHdr;
137   MMRESULT mr = NOERROR;
138   WinSndData *device;
139
140   device = (WinSndData *)dwInstance;
141
142   switch (uMsg)
143     {
144       case MM_WOM_DONE:
145         wHdr = (WAVEHDR *) dwParam1;
146         /* A waveform-audio data block has been played and 
147            can now be freed. */
148         ms_message("WaveInCallback : MM_WOM_DONE");
149         waveInUnprepareHeader (waveindev, (LPWAVEHDR) wHdr, sizeof (WAVEHDR));
150         break;
151
152       case WIM_OPEN:
153         ms_message("WaveInCallback : WIM_OPEN");
154         break;
155       case WIM_CLOSE:
156         ms_message("WaveInCallback : WIM_CLOSE");
157         break;
158       case WIM_DATA:
159         wHdr = (WAVEHDR *) dwParam1;
160
161                 device->bytes_read+=wHdr->dwBytesRecorded;
162
163         if (!device->read_started && !device->write_started)
164           {
165             mr = waveInUnprepareHeader (device->waveindev, (LPWAVEHDR) wHdr, sizeof (WAVEHDR));
166             ms_warning("WaveInCallback : unprepare header (waveInUnprepareHeader:0x%i)", mr);
167             return;
168           }
169
170         if (wHdr->dwBufferLength!=wHdr->dwBytesRecorded)
171         {
172             mr = waveInAddBuffer (device->waveindev,
173                 wHdr,
174                 sizeof (device->waveinhdr[wHdr->dwUser]));
175             if (mr != MMSYSERR_NOERROR)
176             {
177                 ms_warning("WaveInCallback : error adding buffer to sound card (waveInAddBuffer:0x%i)", mr);
178             }
179             return;
180         }
181         ms_mutex_lock(&device->mutex);
182                 if (device->read_started)
183         {
184             mblk_t *rm=NULL;
185             if (rm==NULL) rm=allocb(wHdr->dwBufferLength,0);
186                         memcpy(rm->b_wptr,wHdr->lpData, wHdr->dwBufferLength);
187
188 #ifndef DISABLE_SPEEX
189                         if (device->pst!=NULL)
190                         {
191                                 int vad;
192                                 //memset(rm->b_wptr,0, wHdr->dwBufferLength);
193
194                                 vad = speex_preprocess(device->pst, (short*)rm->b_wptr, NULL);
195 #if 0
196                                 if (vad!=1)
197                             ms_message("WaveInCallback : %d", vad);
198 #endif
199                         }
200
201 #endif
202                         rm->b_wptr+=wHdr->dwBufferLength;
203                         putq(&device->rq,rm);
204                         device->stat_input++;
205                     rm=NULL;
206         }
207         ms_mutex_unlock(&device->mutex);
208
209         mr = waveInAddBuffer (device->waveindev,
210             wHdr,
211             sizeof (device->waveinhdr[wHdr->dwUser]));
212         if (mr != MMSYSERR_NOERROR)
213         {
214             ms_warning("WaveInCallback : error adding buffer to sound card (waveInAddBuffer:0x%i)", mr);
215             return;
216         }
217     }
218 }
219
220 static int winsnd_open(WinSndData *device, int devnumber, int bits,int stereo, int rate, int *minsz)
221 {
222     MMRESULT mr = NOERROR;
223     DWORD dwFlag;
224     int i;
225     int channel = 1;
226     if (stereo>0)
227         channel = stereo;
228         device->wfx.wFormatTag = WAVE_FORMAT_PCM;
229         device->wfx.cbSize = 0;
230         device->wfx.nAvgBytesPerSec = 16000;
231         device->wfx.nBlockAlign = 2;
232         device->wfx.nChannels = channel;
233         device->wfx.nSamplesPerSec = rate; /* 8000; */
234         device->wfx.wBitsPerSample = bits;
235         
236
237     dwFlag = CALLBACK_FUNCTION;
238     if (devnumber != WAVE_MAPPER)
239         dwFlag = WAVE_MAPPED | CALLBACK_FUNCTION;
240     mr = waveOutOpen (&(device->waveoutdev), devnumber, &(device->wfx), (DWORD) SpeakerCallback,
241                     (DWORD)device, dwFlag);
242     if (mr != NOERROR)
243     {
244         ms_warning("Failed to open device: trying default device. (waveOutOpen:0x%i)", mr);
245         dwFlag = CALLBACK_FUNCTION;
246         mr = waveOutOpen (&(device->waveoutdev), WAVE_MAPPER, &(device->wfx), (DWORD) SpeakerCallback,
247                         (DWORD)device, dwFlag);
248     }
249     if (mr != NOERROR)
250     {
251         ms_warning("Failed to open windows sound device. (waveOutOpen:0x%i)", mr);
252         return -1;
253     }
254
255 #if 0
256 #define MM_WOM_SETSECONDARYGAINCLASS   (WM_USER)
257 #define MM_WOM_SETSECONDARYGAINLIMIT   (WM_USER+1)
258 #define MM_WOM_FORCESPEAKER            (WM_USER+2)
259
260         bool bSpeaker=TRUE;
261         mr = waveOutMessage(device->waveoutdev, MM_WOM_FORCESPEAKER, bSpeaker, 0);
262     if (mr != NOERROR)
263     {
264         ms_warning("Failed to use earphone. (waveOutMessage:0x%i)", mr);
265         return -1;
266     }
267
268         typedef HRESULT (* _SetSpeakerMode)(DWORD mode);
269         _SetSpeakerMode pfnSetSpeakerMode;
270
271         HINSTANCE hDll = LoadLibrary(L"\\windows\\ossvcs.dll");
272         //_debug(L"ossvcs.dll h=%X",hDll);
273         pfnSetSpeakerMode = (_SetSpeakerMode)GetProcAddress(hDll,(LPCTSTR)218);
274         if (pfnSetSpeakerMode)
275         {
276         //_debug(L"SetSpeakerMode imported.");
277         DWORD sm = 0;
278         //_debug(L"SpeakerMode set to %d", sm);
279         pfnSetSpeakerMode(sm);
280         }
281         //else
282         //_debug(L"pfnSetSpeakerMode import failed.");
283         FreeLibrary(hDll);
284 #endif
285
286 #ifdef CONTROLVOLUME
287         mr = waveOutGetVolume(device->waveoutdev, &device->dwOldVolume);
288     if (mr != NOERROR)
289     {
290         ms_warning("Failed to get volume device. (waveOutGetVolume:0x%i)", mr);
291     }
292
293         mr = waveOutSetVolume(device->waveoutdev, 0xFFFFFFFF);
294     if (mr != NOERROR)
295     {
296         ms_warning("Failed to set volume device. (waveOutSetVolume:0x%i)", mr);
297     }
298 #endif
299
300     /* prepare windows buffers */
301
302     for (i = 0; i < MAX_WAVEHDR; i++)
303     {
304         memset (&(device->waveouthdr[i]), 0, sizeof (device->waveouthdr[i]));
305         device->waveouthdr[i].lpData = device->waveoutbuffer[i];
306         /* BUG: on ne connait pas la taille des frames a recevoir... 
307         on utilise enc_frame_per_packet au lien de dec_frame_per_packet */
308
309         device->waveouthdr[i].dwBufferLength = device->rate/8000 * WINSND_BUFLEN;
310         /* 480 pour 98 (speex) */
311         device->waveouthdr[i].dwFlags = 0;
312         device->waveouthdr[i].dwUser = i;
313
314         mr = waveOutPrepareHeader (device->waveoutdev, &(device->waveouthdr[i]),
315             sizeof (device->waveouthdr[i]));
316         if (mr != MMSYSERR_NOERROR){
317             ms_warning("Failed to prepare windows sound device. (waveOutPrepareHeader:0x%i)", mr);
318         }
319         else
320         {
321             ms_message("Sound Header prepared %i for windows sound device. (waveOutPrepareHeader)", i);
322         }
323     }
324
325
326     /* Init Microphone device */
327     dwFlag = CALLBACK_FUNCTION;
328     if (devnumber != WAVE_MAPPER)
329         dwFlag = WAVE_MAPPED | CALLBACK_FUNCTION;
330     mr = waveInOpen (&(device->waveindev), devnumber, &(device->wfx),
331                 (DWORD) WaveInCallback, (DWORD)device, dwFlag);
332     if (mr != NOERROR)
333     {
334         ms_warning("Failed to open device: trying default device. (waveInOpen:0x%i)", mr);
335         dwFlag = CALLBACK_FUNCTION;
336         mr = waveInOpen (&(device->waveindev), WAVE_MAPPER, &(device->wfx),
337                     (DWORD) WaveInCallback, (DWORD)device, dwFlag);
338     }
339
340     if (mr != NOERROR)
341     {
342         ms_warning("Failed to prepare windows sound device. (waveInOpen:0x%i)", mr);
343         return -1;
344     }
345
346
347
348     for (i = 0; i < MAX_WAVEHDR; i++)
349     {
350         memset (&(device->waveinhdr[i]), 0, sizeof (device->waveinhdr[i]));
351         device->waveinhdr[i].lpData = device->waveinbuffer[i];
352         /* frameSize */
353         device->waveinhdr[i].dwBufferLength = device->rate/8000 * WINSND_BUFLEN;
354         device->waveinhdr[i].dwFlags = 0;
355         device->waveinhdr[i].dwUser = i;
356         mr = waveInPrepareHeader (device->waveindev, &(device->waveinhdr[i]),             
357             sizeof (device->waveinhdr[i]));
358         if (mr == MMSYSERR_NOERROR){
359             mr = waveInAddBuffer (device->waveindev, &(device->waveinhdr[i]),
360                 sizeof (device->waveinhdr[i]));
361             if (mr == MMSYSERR_NOERROR)
362             {
363                 ms_message("Sound Header prepared %i for windows sound device. (waveInAddBuffer)", i);
364             }
365             else
366             {
367                 ms_warning("Failed to prepare windows sound device. (waveInAddBuffer:0x%i)", mr);
368             }
369         }
370         else
371         {
372             ms_warning("Failed to prepare windows sound device. (waveInPrepareHeader:0x%i)", mr);
373         }
374     }
375
376 #ifndef DISABLE_SPEEX
377 #if 0
378         device->pst = speex_preprocess_state_init((device->rate/8000 * 320)/2, device->rate);
379         if (device->pst!=NULL) {
380                 float f;
381                 i=1;
382                 speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_VAD, &i);
383                 i=1;
384                 speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DENOISE, &i);
385                 i=0;
386                 speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_AGC, &i);
387                 f=8000;
388                 speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_AGC_LEVEL, &f);
389                 i=0;
390                 speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DEREVERB, &i);
391                 f=.4;
392                 speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f);
393                 f=.3;
394                 speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f);
395         }
396 #endif
397 #endif
398
399         mr = waveInStart (device->waveindev);
400     if (mr != MMSYSERR_NOERROR)
401     {
402         ms_warning("Failed to start recording on windows sound device. (waveInStart:0x%i)", mr);
403         return -1;
404     }
405
406         *minsz=device->rate/8000 * 320;
407         return 0;
408 }
409
410 static void winsnd_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent)
411 {
412         WinSndData *d=(WinSndData*)card->data;
413     MMRESULT mr = NOERROR;
414     DWORD dwVolume = 0xFFFF;
415     dwVolume = ((0xFFFF) * percent) / 100;
416
417         if (d->mixdev==NULL) return;
418         switch(e){
419                 case MS_SND_CARD_MASTER:
420             mr = waveOutSetVolume(d->waveoutdev, dwVolume);
421                 if (mr != MMSYSERR_NOERROR)
422                 {
423                 ms_warning("Failed to set master volume. (waveOutSetVolume:0x%i)", mr);
424                 return;
425                 }
426             return;
427         break;
428 #if 0
429         case MS_SND_CARD_CAPTURE:
430                         wincmd=SOUND_MIXER_IGAIN;
431                 break;
432                 case MS_SND_CARD_PLAYBACK:
433                         wincmd=SOUND_MIXER_PCM;
434                 break;
435 #endif
436         default:
437                         ms_warning("winsnd_card_set_level: unsupported command.");
438                         return;
439         }
440 }
441
442 static int winsnd_get_level(MSSndCard *card, MSSndCardMixerElem e)
443 {
444         WinSndData *d=(WinSndData*)card->data;
445     MMRESULT mr = NOERROR;
446     DWORD dwVolume = 0x0000;
447
448         if (d->mixdev==NULL) return -1;
449         switch(e){
450                 case MS_SND_CARD_MASTER:
451             mr=waveOutGetVolume(d->waveoutdev, &dwVolume);
452             // Transform to 0 to 100 scale
453             //dwVolume = (dwVolume *100) / (0xFFFF);
454             return 60;
455         break;
456 #if 0
457         case MS_SND_CARD_CAPTURE:
458                         osscmd=SOUND_MIXER_IGAIN;
459                 break;
460                 case MS_SND_CARD_PLAYBACK:
461                         osscmd=SOUND_MIXER_PCM;
462                 break;
463 #endif
464                 default:
465                         ms_warning("winsnd_card_get_level: unsupported command.");
466                         return -1;
467         }
468         return -1;
469 }
470
471 static void winsnd_set_source(MSSndCard *card, MSSndCardCapture source)
472 {
473         WinSndData *d=(WinSndData*)card->data;
474         if (d->mixdev==NULL) return;
475
476         switch(source){
477                 case MS_SND_CARD_MIC:
478                 break;
479                 case MS_SND_CARD_LINE:
480                 break;
481         }       
482 }
483
484 static void winsnd_init(MSSndCard *card){
485         WinSndData *d=(WinSndData*)ms_new(WinSndData,1);
486     memset(d, 0, sizeof(WinSndData));
487         d->bytes_read=0;
488         d->pcmdev=NULL;
489         d->mixdev=NULL;
490     d->sound_err=-1; /* not opened */
491         d->read_started=FALSE;
492         d->write_started=FALSE;
493         d->bits=16;
494         d->rate=8000;
495         d->stereo=FALSE;
496         qinit(&d->rq);
497         d->bufferizer=ms_bufferizer_new();
498         ms_mutex_init(&d->mutex,NULL);
499         card->data=d;
500 #ifndef DISABLE_SPEEX
501         d->pst=0;
502 #endif
503         d->stat_input=0;
504         d->stat_output=0;
505         d->stat_notplayed=0;
506 }
507
508 static void winsnd_uninit(MSSndCard *card){
509         WinSndData *d=(WinSndData*)card->data;
510         if (d==NULL)
511                 return;
512         if (d->pcmdev!=NULL) ms_free(d->pcmdev);
513         if (d->mixdev!=NULL) ms_free(d->mixdev);
514         ms_bufferizer_destroy(d->bufferizer);
515         flushq(&d->rq,0);
516
517         ms_mutex_destroy(&d->mutex);
518
519 #ifndef DISABLE_SPEEX
520         if (d->pst!=NULL)
521             speex_preprocess_state_destroy(d->pst);
522 #endif
523
524         ms_free(d);
525 }
526
527 #define DSP_NAME "/dev/dsp"
528 #define MIXER_NAME "/dev/mixer"
529
530 static void winsnd_detect(MSSndCardManager *m);
531 static  MSSndCard *winsnd_dup(MSSndCard *obj);
532
533 MSSndCardDesc winsnd_card_desc={
534         "WINSND",
535         winsnd_detect,
536         winsnd_init,
537         winsnd_set_level,
538         winsnd_get_level,
539         winsnd_set_source,
540         NULL,
541         NULL,
542         ms_winsnd_read_new,
543         ms_winsnd_write_new,
544         winsnd_uninit,
545         winsnd_dup
546 };
547
548 static  MSSndCard *winsnd_dup(MSSndCard *obj){
549         MSSndCard *card=ms_snd_card_new(&winsnd_card_desc);
550         WinSndData *dcard=(WinSndData*)card->data;
551         WinSndData *dobj=(WinSndData*)obj->data;
552         dcard->pcmdev=ms_strdup(dobj->pcmdev);
553         dcard->mixdev=ms_strdup(dobj->mixdev);
554         dcard->devid=dobj->devid;
555         card->name=ms_strdup(obj->name);
556         return card;
557 }
558
559 static MSSndCard *winsnd_card_new(const char *pcmdev, const char *mixdev, int id){
560         MSSndCard *card=ms_snd_card_new(&winsnd_card_desc);
561         WinSndData *d=(WinSndData*)card->data;
562         d->pcmdev=ms_strdup(pcmdev);
563         d->mixdev=ms_strdup(mixdev);
564         card->name=ms_strdup(pcmdev);
565         d->devid=id;
566         return card;
567 }
568
569 static void winsnd_detect(MSSndCardManager *m){
570     MMRESULT mr = NOERROR;
571     unsigned int nInDevices = waveInGetNumDevs ();
572     unsigned int item;
573         char pcmdev[1024];
574         char mixdev[1024];
575
576     for (item = 0; item < nInDevices; item++)
577     {
578         WAVEINCAPS caps;
579         mr = waveInGetDevCaps (item, &caps, sizeof (WAVEINCAPS));
580         if (mr == MMSYSERR_NOERROR)
581         {
582             MSSndCard *card;
583                 snprintf(pcmdev,sizeof(pcmdev),"%s",caps.szPname);
584                 snprintf(mixdev,sizeof(mixdev),"%s",caps.szPname);
585             if (item == 0)
586             {
587                         card=winsnd_card_new(pcmdev,mixdev, item-1);
588                         ms_snd_card_manager_add_card(m,card);
589             }
590                         card=winsnd_card_new(pcmdev,mixdev, item);
591                         ms_snd_card_manager_add_card(m,card);
592         }
593     }
594 #if 0
595         nInDevices = mixerGetNumDevs ();
596     for (item = 0; item < nInDevices; item++)
597     {
598         MIXERCAPS caps;
599         mr = mixerGetDevCaps (item, &caps, sizeof (MIXERCAPS));
600         if (mr == MMSYSERR_NOERROR)
601         {
602                 snprintf(pcmdev,sizeof(pcmdev),"%s",caps.szPname);
603                 snprintf(mixdev,sizeof(mixdev),"%s",caps.szPname);
604         }
605     }
606 #endif
607 }
608
609 static void * winsnd_thread(void *p){
610         MSSndCard *card=(MSSndCard*)p;
611         WinSndData *d=(WinSndData*)card->data;
612         int bsize=d->rate/8000 * 320;
613         uint8_t *rtmpbuff=NULL;
614         uint8_t *wtmpbuff=NULL;
615         int err;
616
617         MMRESULT mr = NOERROR;
618     int pos_whdr=0;
619
620         d->stat_input=0;
621         d->stat_output=0;
622         d->stat_notplayed=0;
623         d->sound_err=winsnd_open(d, d->devid, d->bits,d->stereo,d->rate,&bsize);
624         if (d->sound_err==0){
625                 rtmpbuff=(uint8_t*)alloca(bsize);
626                 wtmpbuff=(uint8_t*)alloca(bsize);
627         }
628         while(d->read_started || d->write_started){
629                 if (d->sound_err==0){
630                         if (d->write_started){
631 #if 0
632                 if (d->stat_output>0 && d->buffer_playing==0)
633                                 {
634                     ms_error("No data currently playing in sound card" );
635                                 }
636                                 if (d->stat_output>0 && (d->stat_input-d->stat_output>10 || d->stat_input-d->stat_output<-10))
637                     ms_error("Not perfectly synchronized (input-output=%i)", d->stat_input-d->stat_output);
638 #endif
639
640                                 while (d->buffer_playing<6 && d->buffer_playing<MAX_WAVEHDR)
641                                 {
642                                         ms_mutex_lock(&d->mutex);
643                                     err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize);
644                                         ms_mutex_unlock(&d->mutex);
645                                     if (err!=bsize)
646                                                 break;
647
648                                         ms_mutex_lock(&d->mutex);
649                     /* write to sound devide! */
650                     memcpy (d->waveouthdr[pos_whdr].lpData, wtmpbuff, bsize);
651
652                     mr = waveOutWrite (d->waveoutdev,
653                         &(d->waveouthdr[pos_whdr]),
654                         sizeof (d->waveouthdr[pos_whdr]));
655
656                     if (mr != MMSYSERR_NOERROR)
657                     {
658                         if (mr == WAVERR_STILLPLAYING)
659                         {
660                             /* retry later */
661                             /* data should go back to queue */
662                             /* TODO */
663                             ms_warning("sound device write STILL_PLAYING (waveOutWrite:0x%i)", mr);
664                         }
665                         else
666                         {
667                             ms_warning("sound device write returned (waveOutWrite:0x%i)", mr);
668                         }
669                     }
670                     else
671                     {
672                         d->buffer_playing++;
673                         pos_whdr++;
674                         if (pos_whdr == MAX_WAVEHDR)
675                             pos_whdr = 0;   /* loop over the prepared blocks */
676                     }
677                                         ms_mutex_unlock(&d->mutex);
678
679
680                                     if (err<0){
681 #if !defined(_WIN32_WCE)
682                                             ms_warning("Fail to write %i bytes from soundcard: %s",
683                                                     bsize,strerror(errno));
684 #else
685                                             ms_warning("Fail to write %i bytes from soundcard: %i",
686                                                     bsize,WSAGetLastError());
687 #endif
688                                     }
689                                 }
690
691                 if (d->buffer_playing==6 || d->buffer_playing==MAX_WAVEHDR)
692                 {
693                                         int discarded=0;
694                                         ms_mutex_lock(&d->mutex);
695                                         while (d->bufferizer->size>=bsize){
696                                                 discarded++;
697                                                 d->stat_notplayed++;
698                                             err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize);
699                                         }
700                                         ms_mutex_unlock(&d->mutex);
701                                         if (discarded>0)
702                                                 ms_error("Extra data for sound card removed (%ims), (playing: %i) (input-output: %i)", (discarded*20*320)/320, d->buffer_playing, d->stat_input - d->stat_output);
703                                 }
704 #if !defined(_WIN32_WCE)
705                                 Sleep(5);
706 #endif
707 #if defined(_WIN32_WCE)
708                                 Sleep(10);
709 #endif
710                         }else {
711                                 int discarded=0;
712                                 /* don't think this is usefull, anyway... */
713                                 ms_mutex_lock(&d->mutex);
714                                 while (d->bufferizer->size>=bsize){
715                                         discarded++;
716                                     err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize);
717                                 }
718                                 ms_mutex_unlock(&d->mutex);
719                                 if (discarded>0)
720                                         ms_error("Extra data for sound card removed (%ims), (playing: %i) (input-output: %i)", (discarded*20)/320, d->buffer_playing, d->stat_input - d->stat_output);
721                             Sleep(10);
722             }
723                 }else Sleep(10);
724         }
725         if (d->sound_err==0) {
726         int i;
727         int count=0;
728         /* close sound card */
729                 ms_error("Shutting down sound device (playing: %i) (input-output: %i) (notplayed: %i)", d->buffer_playing, d->stat_input - d->stat_output, d->stat_notplayed);
730
731         /* unprepare buffer */
732         for (i = 0; i < MAX_WAVEHDR; i++)
733         {
734             int counttry=0;
735             for (counttry=0;counttry<10;counttry++)
736             {
737                 mr = waveInUnprepareHeader (d->waveindev,
738                                         &(d->waveinhdr[i]),
739                                         sizeof (d->waveinhdr[i]));
740                 if (mr != MMSYSERR_NOERROR)
741                 {
742                     ms_error("Failed to unprepared %i buffer from sound card (waveInUnprepareHeader:0x%i", count, mr);
743                     Sleep (20);
744                 } else
745                 {
746                     count++;
747                             ms_message("successfully unprepared %i buffer from sound card.", count);
748                     break;
749                 }
750             }
751         }
752                 ms_warning("unprepared %i buffer from sound card.", count);
753
754         mr = waveInStop (d->waveindev);
755         if (mr != MMSYSERR_NOERROR)
756         {
757                 ms_error("failed to stop recording sound card (waveInStop:0x%i)", mr);
758         } else
759         {
760                 ms_message("successfully stopped recording sound card");
761         }
762
763         mr = waveInReset (d->waveindev);
764         if (mr != MMSYSERR_NOERROR)
765         {
766                 ms_warning("failed to reset recording sound card (waveInReset:0x%i)", mr);
767         } else
768         {
769                 ms_message("successful reset of recording sound card");
770         }
771
772         mr = waveInClose (d->waveindev);
773         if (mr != MMSYSERR_NOERROR)
774         {
775                 ms_warning("failed to close recording sound card (waveInClose:0x%i)", mr);
776         } else
777         {
778                 ms_message("successfully closed recording sound card");
779         }
780                 d->sound_err=-1;
781         }
782         d->stat_input=0;
783         d->stat_output=0;
784         d->stat_notplayed=0;
785         return NULL;
786 }
787
788 static void winsnd_start_r(MSSndCard *card){
789         WinSndData *d=(WinSndData*)card->data;
790         if (d->read_started==FALSE && d->write_started==FALSE){
791                 d->read_started=TRUE;
792                 ms_thread_create(&d->thread,NULL,winsnd_thread,card);
793         }else d->read_started=TRUE;
794 }
795
796 static void winsnd_stop_r(MSSndCard *card){
797         WinSndData *d=(WinSndData*)card->data;
798         d->read_started=FALSE;
799         if (d->write_started==FALSE){
800                 ms_thread_join(d->thread,NULL);
801         }
802 }
803
804 static void winsnd_start_w(MSSndCard *card){
805         WinSndData *d=(WinSndData*)card->data;
806         if (d->read_started==FALSE && d->write_started==FALSE){
807                 d->write_started=TRUE;
808                 ms_thread_create(&d->thread,NULL,winsnd_thread,card);
809         }else{
810                 d->write_started=TRUE;
811         }
812 }
813
814 static void winsnd_stop_w(MSSndCard *card){
815         WinSndData *d=(WinSndData*)card->data;
816         d->write_started=FALSE;
817         if (d->read_started==FALSE){
818                 ms_thread_join(d->thread,NULL);
819         }
820 #ifdef CONTROLVOLUME
821         waveOutSetVolume(d->waveoutdev, d->dwOldVolume);
822 #endif
823 }
824
825 static mblk_t *winsnd_get(MSSndCard *card){
826         WinSndData *d=(WinSndData*)card->data;
827         mblk_t *m;
828         ms_mutex_lock(&d->mutex);
829         m=getq(&d->rq);
830         ms_mutex_unlock(&d->mutex);
831         return m;
832 }
833
834 static void winsnd_put(MSSndCard *card, mblk_t *m){
835         WinSndData *d=(WinSndData*)card->data;
836         ms_mutex_lock(&d->mutex);
837         ms_bufferizer_put(d->bufferizer,m);
838         ms_mutex_unlock(&d->mutex);
839 }
840
841
842 static void winsnd_read_preprocess(MSFilter *f){
843         MSSndCard *card=(MSSndCard*)f->data;
844         winsnd_start_r(card);
845         ms_ticker_set_time_func(f->ticker,winsnd_get_cur_time,card->data);
846 }
847
848 static void winsnd_read_postprocess(MSFilter *f){
849         MSSndCard *card=(MSSndCard*)f->data;
850         ms_ticker_set_time_func(f->ticker,NULL,NULL);
851         winsnd_stop_r(card);
852 }
853
854 static void winsnd_read_process(MSFilter *f){
855         MSSndCard *card=(MSSndCard*)f->data;
856         mblk_t *m;
857         while((m=winsnd_get(card))!=NULL){
858                 ms_queue_put(f->outputs[0],m);
859         }
860 }
861
862 static void winsnd_write_preprocess(MSFilter *f){
863         MSSndCard *card=(MSSndCard*)f->data;
864         winsnd_start_w(card);
865 }
866
867 static void winsnd_write_postprocess(MSFilter *f){
868         MSSndCard *card=(MSSndCard*)f->data;
869         winsnd_stop_w(card);
870 }
871
872 static void winsnd_write_process(MSFilter *f){
873         MSSndCard *card=(MSSndCard*)f->data;
874         mblk_t *m;
875
876         while((m=ms_queue_get(f->inputs[0]))!=NULL){
877                 winsnd_put(card,m);
878         }
879 }
880
881 static int set_rate(MSFilter *f, void *arg){
882         MSSndCard *card=(MSSndCard*)f->data;
883         WinSndData *d=(WinSndData*)card->data;
884         d->rate=*((int*)arg);
885         return 0;
886 }
887
888 static int set_nchannels(MSFilter *f, void *arg){
889         MSSndCard *card=(MSSndCard*)f->data;
890         WinSndData *d=(WinSndData*)card->data;
891         d->stereo=(*((int*)arg)==2);
892         return 0;
893 }
894
895 static int winsnd_get_stat_input(MSFilter *f, void *arg){
896         MSSndCard *card=(MSSndCard*)f->data;
897         WinSndData *d=(WinSndData*)card->data;
898
899         return d->stat_input;
900 }
901
902 static int winsnd_get_stat_ouptut(MSFilter *f, void *arg){
903         MSSndCard *card=(MSSndCard*)f->data;
904         WinSndData *d=(WinSndData*)card->data;
905
906         return d->stat_output;
907 }
908
909 static int winsnd_get_stat_discarded(MSFilter *f, void *arg){
910         MSSndCard *card=(MSSndCard*)f->data;
911         WinSndData *d=(WinSndData*)card->data;
912
913         return d->stat_notplayed;
914 }
915
916 static MSFilterMethod winsnd_methods[]={
917         {       MS_FILTER_SET_SAMPLE_RATE       , set_rate      },
918         {       MS_FILTER_SET_NCHANNELS         , set_nchannels },
919         {       MS_FILTER_GET_STAT_INPUT, winsnd_get_stat_input },
920         {       MS_FILTER_GET_STAT_OUTPUT, winsnd_get_stat_ouptut },
921         {       MS_FILTER_GET_STAT_DISCARDED, winsnd_get_stat_discarded },
922         {       0                               , NULL          }
923 };
924
925 MSFilterDesc winsnd_read_desc={
926         MS_WINSND_READ_ID,
927         "MSWinSndRead",
928         "Sound capture filter for Windows Sound drivers",
929         MS_FILTER_OTHER,
930         NULL,
931     0,
932         1,
933         NULL,
934     winsnd_read_preprocess,
935         winsnd_read_process,
936         winsnd_read_postprocess,
937     NULL,
938         winsnd_methods
939 };
940
941
942 MSFilterDesc winsnd_write_desc={
943         MS_WINSND_WRITE_ID,
944         "MSWinSndWrite",
945         "Sound playback filter for Windows Sound drivers",
946         MS_FILTER_OTHER,
947         NULL,
948     1,
949         0,
950         NULL,
951     winsnd_write_preprocess,
952         winsnd_write_process,
953         winsnd_write_postprocess,
954         NULL,
955     winsnd_methods
956 };
957
958 MSFilter *ms_winsnd_read_new(MSSndCard *card){
959         MSFilter *f=ms_filter_new_from_desc(&winsnd_read_desc);
960         f->data=card;
961         return f;
962 }
963
964
965 MSFilter *ms_winsnd_write_new(MSSndCard *card){
966         MSFilter *f=ms_filter_new_from_desc(&winsnd_write_desc);
967         f->data=card;
968         return f;
969 }
970
971 MS_FILTER_DESC_EXPORT(winsnd_read_desc)
972 MS_FILTER_DESC_EXPORT(winsnd_write_desc)