2 mediastreamer2 library - modular sound and video processing and streaming
3 Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org)
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #if defined(_WIN32_WCE)
25 #define WINSND_BUFLEN 320
33 #include <speex/speex_preprocess.h>
36 #include "mediastreamer2/mssndcard.h"
37 #include "mediastreamer2/msfilter.h"
38 #include "mediastreamer2/msticker.h"
41 #include <malloc.h> /* for alloca */
50 MSFilter *ms_winsnd_read_new(MSSndCard *card);
51 MSFilter *ms_winsnd_write_new(MSSndCard *card);
53 typedef struct WinSndData{
63 WAVEHDR waveouthdr[30];
64 char waveoutbuffer[30][3200];
69 WAVEHDR waveinhdr[30];
71 char waveinbuffer[30][3200];
78 MSBufferizer * bufferizer;
84 SpeexPreprocessState *pst;
90 int32_t stat_notplayed;
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);
102 SpeakerCallback (HWAVEOUT _waveoutdev, UINT uMsg, DWORD dwInstance,
103 DWORD dwParam1, DWORD dwParam2)
111 ms_message("SpeakerCallback : WOM_OPEN");
114 ms_message("SpeakerCallback : WOM_CLOSE");
117 wHdr = (WAVEHDR *) dwParam1;
118 device = (WinSndData *)dwInstance;
119 device->buffer_playing--;
120 if (device->stat_output==0)
122 device->stat_input=1; /* reset */
123 device->stat_notplayed=0;
125 device->stat_output++;
133 WaveInCallback (HWAVEIN waveindev, UINT uMsg, DWORD dwInstance, DWORD dwParam1,
137 MMRESULT mr = NOERROR;
140 device = (WinSndData *)dwInstance;
145 wHdr = (WAVEHDR *) dwParam1;
146 /* A waveform-audio data block has been played and
148 ms_message("WaveInCallback : MM_WOM_DONE");
149 waveInUnprepareHeader (waveindev, (LPWAVEHDR) wHdr, sizeof (WAVEHDR));
153 ms_message("WaveInCallback : WIM_OPEN");
156 ms_message("WaveInCallback : WIM_CLOSE");
159 wHdr = (WAVEHDR *) dwParam1;
161 device->bytes_read+=wHdr->dwBytesRecorded;
163 if (!device->read_started && !device->write_started)
165 mr = waveInUnprepareHeader (device->waveindev, (LPWAVEHDR) wHdr, sizeof (WAVEHDR));
166 ms_warning("WaveInCallback : unprepare header (waveInUnprepareHeader:0x%i)", mr);
170 if (wHdr->dwBufferLength!=wHdr->dwBytesRecorded)
172 mr = waveInAddBuffer (device->waveindev,
174 sizeof (device->waveinhdr[wHdr->dwUser]));
175 if (mr != MMSYSERR_NOERROR)
177 ms_warning("WaveInCallback : error adding buffer to sound card (waveInAddBuffer:0x%i)", mr);
181 ms_mutex_lock(&device->mutex);
182 if (device->read_started)
185 if (rm==NULL) rm=allocb(wHdr->dwBufferLength,0);
186 memcpy(rm->b_wptr,wHdr->lpData, wHdr->dwBufferLength);
188 #ifndef DISABLE_SPEEX
189 if (device->pst!=NULL)
192 //memset(rm->b_wptr,0, wHdr->dwBufferLength);
194 vad = speex_preprocess(device->pst, (short*)rm->b_wptr, NULL);
197 ms_message("WaveInCallback : %d", vad);
202 rm->b_wptr+=wHdr->dwBufferLength;
203 putq(&device->rq,rm);
204 device->stat_input++;
207 ms_mutex_unlock(&device->mutex);
209 mr = waveInAddBuffer (device->waveindev,
211 sizeof (device->waveinhdr[wHdr->dwUser]));
212 if (mr != MMSYSERR_NOERROR)
214 ms_warning("WaveInCallback : error adding buffer to sound card (waveInAddBuffer:0x%i)", mr);
220 static int winsnd_open(WinSndData *device, int devnumber, int bits,int stereo, int rate, int *minsz)
222 MMRESULT mr = NOERROR;
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;
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);
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);
251 ms_warning("Failed to open windows sound device. (waveOutOpen:0x%i)", mr);
256 #define MM_WOM_SETSECONDARYGAINCLASS (WM_USER)
257 #define MM_WOM_SETSECONDARYGAINLIMIT (WM_USER+1)
258 #define MM_WOM_FORCESPEAKER (WM_USER+2)
261 mr = waveOutMessage(device->waveoutdev, MM_WOM_FORCESPEAKER, bSpeaker, 0);
264 ms_warning("Failed to use earphone. (waveOutMessage:0x%i)", mr);
268 typedef HRESULT (* _SetSpeakerMode)(DWORD mode);
269 _SetSpeakerMode pfnSetSpeakerMode;
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)
276 //_debug(L"SetSpeakerMode imported.");
278 //_debug(L"SpeakerMode set to %d", sm);
279 pfnSetSpeakerMode(sm);
282 //_debug(L"pfnSetSpeakerMode import failed.");
287 mr = waveOutGetVolume(device->waveoutdev, &device->dwOldVolume);
290 ms_warning("Failed to get volume device. (waveOutGetVolume:0x%i)", mr);
293 mr = waveOutSetVolume(device->waveoutdev, 0xFFFFFFFF);
296 ms_warning("Failed to set volume device. (waveOutSetVolume:0x%i)", mr);
300 /* prepare windows buffers */
302 for (i = 0; i < MAX_WAVEHDR; i++)
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 */
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;
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);
321 ms_message("Sound Header prepared %i for windows sound device. (waveOutPrepareHeader)", i);
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);
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);
342 ms_warning("Failed to prepare windows sound device. (waveInOpen:0x%i)", mr);
348 for (i = 0; i < MAX_WAVEHDR; i++)
350 memset (&(device->waveinhdr[i]), 0, sizeof (device->waveinhdr[i]));
351 device->waveinhdr[i].lpData = device->waveinbuffer[i];
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)
363 ms_message("Sound Header prepared %i for windows sound device. (waveInAddBuffer)", i);
367 ms_warning("Failed to prepare windows sound device. (waveInAddBuffer:0x%i)", mr);
372 ms_warning("Failed to prepare windows sound device. (waveInPrepareHeader:0x%i)", mr);
376 #ifndef DISABLE_SPEEX
378 device->pst = speex_preprocess_state_init((device->rate/8000 * 320)/2, device->rate);
379 if (device->pst!=NULL) {
382 speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_VAD, &i);
384 speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DENOISE, &i);
386 speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_AGC, &i);
388 speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_AGC_LEVEL, &f);
390 speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DEREVERB, &i);
392 speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f);
394 speex_preprocess_ctl(device->pst, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f);
399 mr = waveInStart (device->waveindev);
400 if (mr != MMSYSERR_NOERROR)
402 ms_warning("Failed to start recording on windows sound device. (waveInStart:0x%i)", mr);
406 *minsz=device->rate/8000 * 320;
410 static void winsnd_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent)
412 WinSndData *d=(WinSndData*)card->data;
413 MMRESULT mr = NOERROR;
414 DWORD dwVolume = 0xFFFF;
415 dwVolume = ((0xFFFF) * percent) / 100;
417 if (d->mixdev==NULL) return;
419 case MS_SND_CARD_MASTER:
420 mr = waveOutSetVolume(d->waveoutdev, dwVolume);
421 if (mr != MMSYSERR_NOERROR)
423 ms_warning("Failed to set master volume. (waveOutSetVolume:0x%i)", mr);
429 case MS_SND_CARD_CAPTURE:
430 wincmd=SOUND_MIXER_IGAIN;
432 case MS_SND_CARD_PLAYBACK:
433 wincmd=SOUND_MIXER_PCM;
437 ms_warning("winsnd_card_set_level: unsupported command.");
442 static int winsnd_get_level(MSSndCard *card, MSSndCardMixerElem e)
444 WinSndData *d=(WinSndData*)card->data;
445 MMRESULT mr = NOERROR;
446 DWORD dwVolume = 0x0000;
448 if (d->mixdev==NULL) return -1;
450 case MS_SND_CARD_MASTER:
451 mr=waveOutGetVolume(d->waveoutdev, &dwVolume);
452 // Transform to 0 to 100 scale
453 //dwVolume = (dwVolume *100) / (0xFFFF);
457 case MS_SND_CARD_CAPTURE:
458 osscmd=SOUND_MIXER_IGAIN;
460 case MS_SND_CARD_PLAYBACK:
461 osscmd=SOUND_MIXER_PCM;
465 ms_warning("winsnd_card_get_level: unsupported command.");
471 static void winsnd_set_source(MSSndCard *card, MSSndCardCapture source)
473 WinSndData *d=(WinSndData*)card->data;
474 if (d->mixdev==NULL) return;
477 case MS_SND_CARD_MIC:
479 case MS_SND_CARD_LINE:
484 static void winsnd_init(MSSndCard *card){
485 WinSndData *d=(WinSndData*)ms_new(WinSndData,1);
486 memset(d, 0, sizeof(WinSndData));
490 d->sound_err=-1; /* not opened */
491 d->read_started=FALSE;
492 d->write_started=FALSE;
497 d->bufferizer=ms_bufferizer_new();
498 ms_mutex_init(&d->mutex,NULL);
500 #ifndef DISABLE_SPEEX
508 static void winsnd_uninit(MSSndCard *card){
509 WinSndData *d=(WinSndData*)card->data;
512 if (d->pcmdev!=NULL) ms_free(d->pcmdev);
513 if (d->mixdev!=NULL) ms_free(d->mixdev);
514 ms_bufferizer_destroy(d->bufferizer);
517 ms_mutex_destroy(&d->mutex);
519 #ifndef DISABLE_SPEEX
521 speex_preprocess_state_destroy(d->pst);
527 #define DSP_NAME "/dev/dsp"
528 #define MIXER_NAME "/dev/mixer"
530 static void winsnd_detect(MSSndCardManager *m);
531 static MSSndCard *winsnd_dup(MSSndCard *obj);
533 MSSndCardDesc winsnd_card_desc={
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);
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);
569 static void winsnd_detect(MSSndCardManager *m){
570 MMRESULT mr = NOERROR;
571 unsigned int nInDevices = waveInGetNumDevs ();
576 for (item = 0; item < nInDevices; item++)
579 mr = waveInGetDevCaps (item, &caps, sizeof (WAVEINCAPS));
580 if (mr == MMSYSERR_NOERROR)
583 snprintf(pcmdev,sizeof(pcmdev),"%s",caps.szPname);
584 snprintf(mixdev,sizeof(mixdev),"%s",caps.szPname);
587 card=winsnd_card_new(pcmdev,mixdev, item-1);
588 ms_snd_card_manager_add_card(m,card);
590 card=winsnd_card_new(pcmdev,mixdev, item);
591 ms_snd_card_manager_add_card(m,card);
595 nInDevices = mixerGetNumDevs ();
596 for (item = 0; item < nInDevices; item++)
599 mr = mixerGetDevCaps (item, &caps, sizeof (MIXERCAPS));
600 if (mr == MMSYSERR_NOERROR)
602 snprintf(pcmdev,sizeof(pcmdev),"%s",caps.szPname);
603 snprintf(mixdev,sizeof(mixdev),"%s",caps.szPname);
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;
617 MMRESULT mr = NOERROR;
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);
628 while(d->read_started || d->write_started){
629 if (d->sound_err==0){
630 if (d->write_started){
632 if (d->stat_output>0 && d->buffer_playing==0)
634 ms_error("No data currently playing in sound card" );
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);
640 while (d->buffer_playing<6 && d->buffer_playing<MAX_WAVEHDR)
642 ms_mutex_lock(&d->mutex);
643 err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize);
644 ms_mutex_unlock(&d->mutex);
648 ms_mutex_lock(&d->mutex);
649 /* write to sound devide! */
650 memcpy (d->waveouthdr[pos_whdr].lpData, wtmpbuff, bsize);
652 mr = waveOutWrite (d->waveoutdev,
653 &(d->waveouthdr[pos_whdr]),
654 sizeof (d->waveouthdr[pos_whdr]));
656 if (mr != MMSYSERR_NOERROR)
658 if (mr == WAVERR_STILLPLAYING)
661 /* data should go back to queue */
663 ms_warning("sound device write STILL_PLAYING (waveOutWrite:0x%i)", mr);
667 ms_warning("sound device write returned (waveOutWrite:0x%i)", mr);
674 if (pos_whdr == MAX_WAVEHDR)
675 pos_whdr = 0; /* loop over the prepared blocks */
677 ms_mutex_unlock(&d->mutex);
681 #if !defined(_WIN32_WCE)
682 ms_warning("Fail to write %i bytes from soundcard: %s",
683 bsize,strerror(errno));
685 ms_warning("Fail to write %i bytes from soundcard: %i",
686 bsize,WSAGetLastError());
691 if (d->buffer_playing==6 || d->buffer_playing==MAX_WAVEHDR)
694 ms_mutex_lock(&d->mutex);
695 while (d->bufferizer->size>=bsize){
698 err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize);
700 ms_mutex_unlock(&d->mutex);
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);
704 #if !defined(_WIN32_WCE)
707 #if defined(_WIN32_WCE)
712 /* don't think this is usefull, anyway... */
713 ms_mutex_lock(&d->mutex);
714 while (d->bufferizer->size>=bsize){
716 err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize);
718 ms_mutex_unlock(&d->mutex);
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);
725 if (d->sound_err==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);
731 /* unprepare buffer */
732 for (i = 0; i < MAX_WAVEHDR; i++)
735 for (counttry=0;counttry<10;counttry++)
737 mr = waveInUnprepareHeader (d->waveindev,
739 sizeof (d->waveinhdr[i]));
740 if (mr != MMSYSERR_NOERROR)
742 ms_error("Failed to unprepared %i buffer from sound card (waveInUnprepareHeader:0x%i", count, mr);
747 ms_message("successfully unprepared %i buffer from sound card.", count);
752 ms_warning("unprepared %i buffer from sound card.", count);
754 mr = waveInStop (d->waveindev);
755 if (mr != MMSYSERR_NOERROR)
757 ms_error("failed to stop recording sound card (waveInStop:0x%i)", mr);
760 ms_message("successfully stopped recording sound card");
763 mr = waveInReset (d->waveindev);
764 if (mr != MMSYSERR_NOERROR)
766 ms_warning("failed to reset recording sound card (waveInReset:0x%i)", mr);
769 ms_message("successful reset of recording sound card");
772 mr = waveInClose (d->waveindev);
773 if (mr != MMSYSERR_NOERROR)
775 ms_warning("failed to close recording sound card (waveInClose:0x%i)", mr);
778 ms_message("successfully closed recording sound card");
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;
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);
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);
810 d->write_started=TRUE;
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);
821 waveOutSetVolume(d->waveoutdev, d->dwOldVolume);
825 static mblk_t *winsnd_get(MSSndCard *card){
826 WinSndData *d=(WinSndData*)card->data;
828 ms_mutex_lock(&d->mutex);
830 ms_mutex_unlock(&d->mutex);
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);
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);
848 static void winsnd_read_postprocess(MSFilter *f){
849 MSSndCard *card=(MSSndCard*)f->data;
850 ms_ticker_set_time_func(f->ticker,NULL,NULL);
854 static void winsnd_read_process(MSFilter *f){
855 MSSndCard *card=(MSSndCard*)f->data;
857 while((m=winsnd_get(card))!=NULL){
858 ms_queue_put(f->outputs[0],m);
862 static void winsnd_write_preprocess(MSFilter *f){
863 MSSndCard *card=(MSSndCard*)f->data;
864 winsnd_start_w(card);
867 static void winsnd_write_postprocess(MSFilter *f){
868 MSSndCard *card=(MSSndCard*)f->data;
872 static void winsnd_write_process(MSFilter *f){
873 MSSndCard *card=(MSSndCard*)f->data;
876 while((m=ms_queue_get(f->inputs[0]))!=NULL){
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);
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);
895 static int winsnd_get_stat_input(MSFilter *f, void *arg){
896 MSSndCard *card=(MSSndCard*)f->data;
897 WinSndData *d=(WinSndData*)card->data;
899 return d->stat_input;
902 static int winsnd_get_stat_ouptut(MSFilter *f, void *arg){
903 MSSndCard *card=(MSSndCard*)f->data;
904 WinSndData *d=(WinSndData*)card->data;
906 return d->stat_output;
909 static int winsnd_get_stat_discarded(MSFilter *f, void *arg){
910 MSSndCard *card=(MSSndCard*)f->data;
911 WinSndData *d=(WinSndData*)card->data;
913 return d->stat_notplayed;
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 },
925 MSFilterDesc winsnd_read_desc={
928 "Sound capture filter for Windows Sound drivers",
934 winsnd_read_preprocess,
936 winsnd_read_postprocess,
942 MSFilterDesc winsnd_write_desc={
945 "Sound playback filter for Windows Sound drivers",
951 winsnd_write_preprocess,
952 winsnd_write_process,
953 winsnd_write_postprocess,
958 MSFilter *ms_winsnd_read_new(MSSndCard *card){
959 MSFilter *f=ms_filter_new_from_desc(&winsnd_read_desc);
965 MSFilter *ms_winsnd_write_new(MSSndCard *card){
966 MSFilter *f=ms_filter_new_from_desc(&winsnd_write_desc);
971 MS_FILTER_DESC_EXPORT(winsnd_read_desc)
972 MS_FILTER_DESC_EXPORT(winsnd_write_desc)