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.
24 #include "mediastreamer2/mssndcard.h"
25 #include "mediastreamer2/msfilter.h"
26 #include "mediastreamer2/msticker.h"
34 #if defined(_WIN32_WCE)
35 /*#define DISABLE_SPEEX */
36 /*#define WCE_OPTICON_WORKAROUND 1000 */
39 #include <speex/speex_preprocess.h>
42 #define WINSND_NBUFS 10
43 #define WINSND_OUT_NBUFS 20
44 #define WINSND_NSAMPLES 160
45 #define WINSND_MINIMUMBUFFER 5
47 static MSFilter *ms_winsnd_read_new(MSSndCard *card);
48 static MSFilter *ms_winsnd_write_new(MSSndCard *card);
50 typedef struct WinSndCard{
56 static void winsndcard_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent){
57 WinSndCard *d=(WinSndCard*)card->data;
65 MIXERLINECONTROLS mlc = {0};
66 MIXERCONTROL mc = {0};
67 MIXERCONTROLDETAILS mcd = {0};
68 MIXERCONTROLDETAILS_UNSIGNED mcdu = {0};
70 MMRESULT mr = MMSYSERR_NOERROR;
71 DWORD dwVolume = ((0xFFFF) * percent) / 100;
73 WORD wLeftVol, wRightVol;
75 wLeftVol = LOWORD(dwVolume); // get higher WORD
76 wRightVol = LOWORD(dwVolume); // get lower WORD
78 dwNewVol = MAKELONG(wLeftVol, wRightVol);
81 case MS_SND_CARD_PLAYBACK:
82 case MS_SND_CARD_MASTER:
84 mr = mixerGetID( (HMIXEROBJ)d->out_devid, &uMixerID, MIXER_OBJECTF_WAVEOUT );
85 if ( mr != MMSYSERR_NOERROR )
87 ms_error("winsndcard_set_level: mixerGetID failed. (0x%x)", mr);
90 mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
91 if ( mr != MMSYSERR_NOERROR )
93 mixerClose( (HMIXER)dwMixerHandle );
94 ms_error("winsndcard_set_level: mixerOpen failed. (0x%x)", mr);
97 memset( &MixerLine, 0, sizeof(MIXERLINE) );
98 MixerLine.cbStruct = sizeof(MIXERLINE);
99 if (MS_SND_CARD_MASTER==e)
100 MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
102 MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
103 mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE );
104 if ( mr != MMSYSERR_NOERROR )
106 mixerClose( (HMIXER)dwMixerHandle );
107 ms_error("winsndcard_set_level: mixerGetLineInfo failed. (0x%x)", mr);
111 /* ms_message("Name: %s\n", MixerLine.szName); */
112 /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
113 /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
115 mlc.cbStruct = sizeof(MIXERLINECONTROLS);
116 mlc.dwLineID = MixerLine.dwLineID;
117 mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
120 mlc.cbmxctrl = sizeof(MIXERCONTROL);
121 mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle,
122 &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
125 mcdu.dwValue = 65535*percent/100; /* the volume is a number between 0 and 65535 */
127 mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
129 mcd.dwControlID = mc.dwControlID;
130 mcd.paDetails = &mcdu;
131 mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
133 mr = mixerSetControlDetails((HMIXEROBJ)dwMixerHandle,
134 &mcd, MIXER_SETCONTROLDETAILSF_VALUE);
136 if (mr != MMSYSERR_NOERROR)
138 ms_error("winsndcard_set_level: mixerSetControlDetails failed. (0x%x)", mr);
143 case MS_SND_CARD_CAPTURE:
144 mr = mixerGetID( (HMIXEROBJ)d->in_devid, &uMixerID, MIXER_OBJECTF_WAVEIN );
145 if ( mr != MMSYSERR_NOERROR )
147 ms_error("winsndcard_set_level: mixerGetID failed. (0x%x)", mr);
150 mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
151 if ( mr != MMSYSERR_NOERROR )
153 mixerClose( (HMIXER)dwMixerHandle );
154 ms_error("winsndcard_set_level: mixerGetLineInfo failed. (0x%x)", mr);
157 memset( &MixerLine, 0, sizeof(MIXERLINE) );
158 MixerLine.cbStruct = sizeof(MIXERLINE);
159 MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
160 mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE );
161 if ( mr != MMSYSERR_NOERROR )
163 mixerClose( (HMIXER)dwMixerHandle );
164 ms_error("winsndcard_set_level: mixerGetLineInfo failed. (0x%x)", mr);
167 /* ms_message("Name: %s\n", MixerLine.szName); */
168 /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
169 /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
171 mlc.cbStruct = sizeof(MIXERLINECONTROLS);
172 mlc.dwLineID = MixerLine.dwLineID;
173 mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
176 mlc.cbmxctrl = sizeof(MIXERCONTROL);
177 mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle,
178 &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
180 if (mr == MMSYSERR_NOERROR)
182 mcdu.dwValue = 65535*percent/100; /* the volume is a number between 0 and 65535 */
184 mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
186 mcd.dwControlID = mc.dwControlID;
187 mcd.paDetails = &mcdu;
188 mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
190 mr = mixerSetControlDetails((HMIXEROBJ)dwMixerHandle,
191 &mcd, MIXER_SETCONTROLDETAILSF_VALUE);
193 if (mr == MMSYSERR_NOERROR)
197 ms_error("winsndcard_set_level: mixerSetControlDetails failed. (0x%x)", mr);
198 ms_warning("winsndcard_set_level: control the SRC_MICROPHONE instead");
202 ms_error("winsndcard_set_level: mixerGetLineControls failed. (0x%x)", mr);
203 ms_warning("winsndcard_set_level: control the SRC_MICROPHONE instead");
206 /* In case capture doesn't work: use the SRC_MICROPHONE volume */
208 for (uLineIndex = 0; uLineIndex < MixerLine.cConnections; uLineIndex++)
210 memset( &Line, 0, sizeof(MIXERLINE) );
211 Line.cbStruct = sizeof(MIXERLINE);
212 Line.dwDestination = MixerLine.dwDestination;
213 Line.dwSource = uLineIndex;
214 mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &Line, MIXER_GETLINEINFOF_LINEID);
215 if ( mr != MMSYSERR_NOERROR )
217 mixerClose( (HMIXER)dwMixerHandle );
218 ms_error("winsndcard_set_level: mixerGetLineInfo failed. (0x%x)", mr);
222 /* ms_message("Name: %s\n", MixerLine.szName); */
223 /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
224 /* ms_message("LineID: %d\n", MixerLine.dwLineID); */
225 /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
227 memset( &Line, 0, sizeof(MIXERLINE) );
228 Line.cbStruct = sizeof(MIXERLINE);
229 Line.dwDestination = MixerLine.dwDestination;
230 Line.dwSource = uLineIndex;
231 mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &Line, MIXER_GETLINEINFOF_SOURCE);
232 if ( mr != MMSYSERR_NOERROR )
234 mixerClose( (HMIXER)dwMixerHandle );
235 ms_error("winsndcard_set_level: mixerGetLineInfo failed. (0x%x)", mr);
239 /* ms_message("Name: %s\n", MixerLine.szName); */
240 /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
241 /* ms_message("LineID: %d\n", MixerLine.dwLineID); */
242 /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
244 if (MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE == Line.dwComponentType)
246 LPMIXERCONTROL pmxctrl = (LPMIXERCONTROL)malloc(sizeof(MIXERCONTROL));
247 MIXERLINECONTROLS mxlctrl = {sizeof(mxlctrl), Line.dwLineID, MIXERCONTROL_CONTROLTYPE_VOLUME, 1, sizeof(MIXERCONTROL), pmxctrl};
248 if(!mixerGetLineControls((HMIXEROBJ)dwMixerHandle, &mxlctrl,
249 MIXER_GETLINECONTROLSF_ONEBYTYPE)){
250 DWORD cChannels = Line.cChannels;
251 LPMIXERCONTROLDETAILS_UNSIGNED pUnsigned;
252 MIXERCONTROLDETAILS mxcd;
253 if (MIXERCONTROL_CONTROLF_UNIFORM & pmxctrl->fdwControl)
256 (LPMIXERCONTROLDETAILS_UNSIGNED)
257 malloc(cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
259 mxcd.cbStruct = sizeof(mxcd);
260 mxcd.dwControlID = pmxctrl->dwControlID;
261 mxcd.cChannels = cChannels;
262 mxcd.hwndOwner = (HWND)0;
263 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
264 mxcd.paDetails = (LPVOID) pUnsigned;
266 mixerGetControlDetails((HMIXEROBJ)dwMixerHandle, &mxcd,
267 MIXER_SETCONTROLDETAILSF_VALUE);
268 pUnsigned[0].dwValue = pUnsigned[cChannels - 1].dwValue
269 = pmxctrl->Bounds.dwMaximum*percent/100;
270 mixerSetControlDetails((HMIXEROBJ)dwMixerHandle, &mxcd,
271 MIXER_SETCONTROLDETAILSF_VALUE);
279 mixerClose( (HMIXER)dwMixerHandle );
280 if (mr != MMSYSERR_NOERROR)
282 ms_error("winsndcard_set_level: mixerClose failed. (0x%x)", mr);
287 ms_warning("winsnd_card_set_level: unsupported command.");
291 static int winsndcard_get_level(MSSndCard *card, MSSndCardMixerElem e){
292 WinSndCard *d=(WinSndCard*)card->data;
300 MIXERLINECONTROLS mlc = {0};
301 MIXERCONTROL mc = {0};
302 MIXERCONTROLDETAILS mcd = {0};
303 MIXERCONTROLDETAILS_UNSIGNED mcdu = {0};
305 MMRESULT mr = MMSYSERR_NOERROR;
309 case MS_SND_CARD_MASTER:
310 case MS_SND_CARD_PLAYBACK:
312 mr = mixerGetID( (HMIXEROBJ)d->out_devid, &uMixerID, MIXER_OBJECTF_WAVEOUT );
313 if ( mr != MMSYSERR_NOERROR )
315 ms_error("winsndcard_get_level: mixerGetID failed. (0x%x)", mr);
318 mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
319 if ( mr != MMSYSERR_NOERROR )
321 mixerClose( (HMIXER)dwMixerHandle );
322 ms_error("winsndcard_get_level: mixerOpen failed. (0x%x)", mr);
325 memset( &MixerLine, 0, sizeof(MIXERLINE) );
326 MixerLine.cbStruct = sizeof(MIXERLINE);
327 if (MS_SND_CARD_MASTER==e)
328 MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
330 MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
331 mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE );
332 if ( mr != MMSYSERR_NOERROR )
334 mixerClose( (HMIXER)dwMixerHandle );
335 ms_error("winsndcard_get_level: mixerGetLineInfo failed. (0x%x)", mr);
339 /* ms_message("Name: %s\n", MixerLine.szName); */
340 /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
341 /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
343 mlc.cbStruct = sizeof(MIXERLINECONTROLS);
344 mlc.dwLineID = MixerLine.dwLineID;
345 mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
348 mlc.cbmxctrl = sizeof(MIXERCONTROL);
349 mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle,
350 &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
351 if (mr != MMSYSERR_NOERROR)
353 ms_error("winsndcard_get_level: mixerGetLineControls failed. (0x%x)", mr);
357 mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
359 mcd.dwControlID = mc.dwControlID;
360 mcd.paDetails = &mcdu;
361 mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
363 mr = mixerGetControlDetails((HMIXEROBJ)dwMixerHandle, &mcd,
364 MIXER_SETCONTROLDETAILSF_VALUE);
365 percent = (mcdu.dwValue *100) / (mc.Bounds.dwMaximum);
367 if (mr != MMSYSERR_NOERROR)
369 ms_error("winsndcard_get_level: mixerGetControlDetails failed. (0x%x)", mr);
375 case MS_SND_CARD_CAPTURE:
376 mr = mixerGetID( (HMIXEROBJ)d->in_devid, &uMixerID, MIXER_OBJECTF_WAVEIN );
377 if ( mr != MMSYSERR_NOERROR )
379 ms_error("winsndcard_get_level: mixerGetID failed. (0x%x)", mr);
382 mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
383 if ( mr != MMSYSERR_NOERROR )
385 mixerClose( (HMIXER)dwMixerHandle );
386 ms_error("winsndcard_get_level: mixerOpen failed. (0x%x)", mr);
389 memset( &MixerLine, 0, sizeof(MIXERLINE) );
390 MixerLine.cbStruct = sizeof(MIXERLINE);
391 MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
392 mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE );
393 if ( mr != MMSYSERR_NOERROR )
395 mixerClose( (HMIXER)dwMixerHandle );
396 ms_error("winsndcard_get_level: mixerGetLineInfo failed. (0x%x)", mr);
400 mlc.cbStruct = sizeof(MIXERLINECONTROLS);
401 mlc.dwLineID = MixerLine.dwLineID;
402 mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
405 mlc.cbmxctrl = sizeof(MIXERCONTROL);
406 mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle,
407 &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
408 if (mr == MMSYSERR_NOERROR)
410 mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
412 mcd.dwControlID = mc.dwControlID;
413 mcd.paDetails = &mcdu;
414 mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
416 mr = mixerGetControlDetails((HMIXEROBJ)dwMixerHandle, &mcd,
417 MIXER_SETCONTROLDETAILSF_VALUE);
418 percent = (mcdu.dwValue *100) / (mc.Bounds.dwMaximum);
420 if (mr == MMSYSERR_NOERROR)
424 ms_error("winsndcard_get_level: mixerGetControlDetails failed. (0x%x)", mr);
425 ms_warning("winsndcard_get_level: control the SRC_MICROPHONE instead");
429 ms_error("winsndcard_get_level: mixerGetLineControls failed. (0x%x)", mr);
430 ms_warning("winsndcard_get_level: control the SRC_MICROPHONE instead");
433 /* ms_message("Name: %s\n", MixerLine.szName); */
434 /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
435 /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
437 for (uLineIndex = 0; uLineIndex < MixerLine.cConnections; uLineIndex++)
439 memset( &Line, 0, sizeof(MIXERLINE) );
440 Line.cbStruct = sizeof(MIXERLINE);
441 Line.dwDestination = MixerLine.dwDestination;
442 Line.dwSource = uLineIndex;
443 mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &Line, MIXER_GETLINEINFOF_LINEID);
444 if ( mr != MMSYSERR_NOERROR )
446 mixerClose( (HMIXER)dwMixerHandle );
447 ms_error("winsndcard_get_level: mixerGetLineInfo failed. (0x%x)", mr);
451 /* ms_message("Name: %s\n", MixerLine.szName); */
452 /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
453 /* ms_message("LineID: %d\n", MixerLine.dwLineID); */
454 /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
456 memset( &Line, 0, sizeof(MIXERLINE) );
457 Line.cbStruct = sizeof(MIXERLINE);
458 Line.dwDestination = MixerLine.dwDestination;
459 Line.dwSource = uLineIndex;
460 mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &Line, MIXER_GETLINEINFOF_SOURCE);
461 if ( mr != MMSYSERR_NOERROR )
463 mixerClose( (HMIXER)dwMixerHandle );
464 ms_error("winsndcard_get_level: mixerGetLineInfo failed. (0x%x)", mr);
468 /* ms_message("Name: %s\n", MixerLine.szName); */
469 /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
470 /* ms_message("LineID: %d\n", MixerLine.dwLineID); */
471 /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
473 if (MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE == Line.dwComponentType)
475 LPMIXERCONTROL pmxctrl = (LPMIXERCONTROL)malloc(sizeof(MIXERCONTROL));
476 MIXERLINECONTROLS mxlctrl = {sizeof(mxlctrl), Line.dwLineID, MIXERCONTROL_CONTROLTYPE_VOLUME, 1, sizeof(MIXERCONTROL), pmxctrl};
477 if(!mixerGetLineControls((HMIXEROBJ)dwMixerHandle, &mxlctrl,
478 MIXER_GETLINECONTROLSF_ONEBYTYPE)){
479 DWORD cChannels = Line.cChannels;
480 LPMIXERCONTROLDETAILS_UNSIGNED pUnsigned;
481 MIXERCONTROLDETAILS mxcd;
482 if (MIXERCONTROL_CONTROLF_UNIFORM & pmxctrl->fdwControl)
485 (LPMIXERCONTROLDETAILS_UNSIGNED)
486 malloc(cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
488 mxcd.cbStruct = sizeof(mxcd);
489 mxcd.dwControlID = pmxctrl->dwControlID;
490 mxcd.cChannels = cChannels;
491 mxcd.hwndOwner = (HWND)0;
492 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
493 mxcd.paDetails = (LPVOID) pUnsigned;
495 mixerGetControlDetails((HMIXEROBJ)dwMixerHandle, &mxcd,
496 MIXER_SETCONTROLDETAILSF_VALUE);
497 percent = (pUnsigned[0].dwValue *100) / (pmxctrl->Bounds.dwMaximum);
505 mixerClose( (HMIXER)dwMixerHandle );
506 if (mr != MMSYSERR_NOERROR)
508 ms_error("winsndcard_get_level: mixerClose failed. (0x%x)", mr);
514 ms_warning("winsndcard_get_level: unsupported command.");
520 static void winsndcard_set_source(MSSndCard *card, MSSndCardCapture source){
523 case MS_SND_CARD_MIC:
525 case MS_SND_CARD_LINE:
530 static int winsndcard_set_control(MSSndCard *card, MSSndCardControlElem e, int val){
531 WinSndCard *d=(WinSndCard*)card->data;
539 MIXERLINECONTROLS mlc = {0};
540 MIXERCONTROL mc = {0};
541 MIXERCONTROLDETAILS mcd = {0};
542 MIXERCONTROLDETAILS_BOOLEAN bMute;
544 MMRESULT mr = MMSYSERR_NOERROR;
547 case MS_SND_CARD_CAPTURE_MUTE:
549 bMute.fValue = (val>0);
551 mr = mixerGetID( (HMIXEROBJ)d->in_devid, &uMixerID, MIXER_OBJECTF_WAVEIN );
552 if ( mr != MMSYSERR_NOERROR )
554 ms_error("winsndcard_set_control: mixerGetID failed. (0x%x)", mr);
557 mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
558 if ( mr != MMSYSERR_NOERROR )
560 mixerClose( (HMIXER)dwMixerHandle );
561 ms_error("winsndcard_set_control: mixerOpen failed. (0x%x)", mr);
564 memset( &MixerLine, 0, sizeof(MIXERLINE) );
565 MixerLine.cbStruct = sizeof(MIXERLINE);
566 MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
567 mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE );
568 if ( mr != MMSYSERR_NOERROR )
570 mixerClose( (HMIXER)dwMixerHandle );
571 ms_error("winsndcard_set_control: mixerGetLineInfo failed. (0x%x)", mr);
574 /* ms_message("Name: %s\n", MixerLine.szName); */
575 /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
576 /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
578 for (uLineIndex = 0; uLineIndex < MixerLine.cConnections; uLineIndex++)
580 memset( &Line, 0, sizeof(MIXERLINE) );
581 Line.cbStruct = sizeof(MIXERLINE);
582 Line.dwDestination = MixerLine.dwDestination;
583 Line.dwSource = uLineIndex;
584 mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &Line, MIXER_GETLINEINFOF_LINEID);
585 if ( mr != MMSYSERR_NOERROR )
587 mixerClose( (HMIXER)dwMixerHandle );
588 ms_error("winsndcard_set_control: mixerGetLineInfo failed. (0x%x)", mr);
592 /* ms_message("Name: %s\n", MixerLine.szName); */
593 /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
594 /* ms_message("LineID: %d\n", MixerLine.dwLineID); */
595 /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
597 memset( &Line, 0, sizeof(MIXERLINE) );
598 Line.cbStruct = sizeof(MIXERLINE);
599 Line.dwDestination = MixerLine.dwDestination;
600 Line.dwSource = uLineIndex;
601 mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &Line, MIXER_GETLINEINFOF_SOURCE);
602 if ( mr != MMSYSERR_NOERROR )
604 mixerClose( (HMIXER)dwMixerHandle );
605 ms_error("winsndcard_set_control: mixerGetLineInfo failed. (0x%x)", mr);
609 /* ms_message("Name: %s\n", MixerLine.szName); */
610 /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
611 /* ms_message("LineID: %d\n", MixerLine.dwLineID); */
612 /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
614 if (MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE == Line.dwComponentType)
617 /* Find a mute control, if any, of the microphone line */
619 LPMIXERCONTROL pmxctrl = (LPMIXERCONTROL)malloc(sizeof(MIXERCONTROL));
620 MIXERLINECONTROLS mxlctrl = {sizeof(mxlctrl), Line.dwLineID, MIXERCONTROL_CONTROLTYPE_MUTE, 1, sizeof(MIXERCONTROL), pmxctrl};
621 if(!mixerGetLineControls((HMIXEROBJ)dwMixerHandle, &mxlctrl, MIXER_GETLINECONTROLSF_ONEBYTYPE)){
622 DWORD cChannels = Line.cChannels;
623 LPMIXERCONTROLDETAILS_BOOLEAN pbool;
624 MIXERCONTROLDETAILS mxcd;
626 if (MIXERCONTROL_CONTROLF_UNIFORM & pmxctrl->fdwControl)
628 pbool = (LPMIXERCONTROLDETAILS_BOOLEAN) malloc(cChannels * sizeof(
629 MIXERCONTROLDETAILS_BOOLEAN));
631 mxcd.cbStruct = sizeof(mxcd);
632 mxcd.dwControlID = pmxctrl->dwControlID;
633 mxcd.cChannels = cChannels;
634 mxcd.hwndOwner = (HWND)0;
635 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
636 mxcd.paDetails = (LPVOID) pbool;
638 mixerGetControlDetails((HMIXEROBJ)dwMixerHandle, &mxcd,
639 MIXER_SETCONTROLDETAILSF_VALUE);
640 /* Unmute the microphone line (for both channels) */
641 pbool[0].fValue = pbool[cChannels - 1].fValue = val; /* 0 -> unmute; */
642 mixerSetControlDetails((HMIXEROBJ)dwMixerHandle, &mxcd,
643 MIXER_SETCONTROLDETAILSF_VALUE);
651 mixerClose( (HMIXER)dwMixerHandle );
652 if (mr != MMSYSERR_NOERROR)
654 ms_error("winsndcard_set_control: mixerClose failed. (0x%x)", mr);
659 case MS_SND_CARD_MASTER_MUTE:
660 case MS_SND_CARD_PLAYBACK_MUTE:
662 bMute.fValue = (val>0);
664 mr = mixerGetID( (HMIXEROBJ)d->out_devid, &uMixerID, MIXER_OBJECTF_WAVEOUT );
665 if ( mr != MMSYSERR_NOERROR )
667 ms_error("winsndcard_set_control: mixerGetID failed. (0x%x)", mr);
670 mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
671 if ( mr != MMSYSERR_NOERROR )
673 mixerClose( (HMIXER)dwMixerHandle );
674 ms_error("winsndcard_set_control: mixerOpen failed. (0x%x)", mr);
677 memset( &MixerLine, 0, sizeof(MIXERLINE) );
678 MixerLine.cbStruct = sizeof(MIXERLINE);
679 if (MS_SND_CARD_MASTER_MUTE==e)
680 MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
682 MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
683 mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE );
684 if ( mr != MMSYSERR_NOERROR )
686 mixerClose( (HMIXER)dwMixerHandle );
687 ms_error("winsndcard_set_control: mixerSetControlDetails failed. (0x%x)", mr);
691 /* ms_message("Name: %s\n", MixerLine.szName); */
692 /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
693 /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
695 mlc.cbStruct = sizeof(MIXERLINECONTROLS);
696 mlc.dwLineID = MixerLine.dwLineID;
697 mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE; //MIXERCONTROL_CONTROLTYPE_VOLUME;
700 mlc.cbmxctrl = sizeof(MIXERCONTROL);
701 mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle,
702 &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
704 mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
706 mcd.dwControlID = mc.dwControlID;
707 mcd.paDetails = &bMute;
708 mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
710 mr = mixerSetControlDetails((HMIXEROBJ)dwMixerHandle,
711 &mcd, MIXER_SETCONTROLDETAILSF_VALUE);
713 if (mr != MMSYSERR_NOERROR)
715 ms_error("winsndcard_set_control: mixerSetControlDetails failed. (0x%x)", mr);
722 ms_warning("winsndcard_set_control: unsupported command.");
727 static int winsndcard_get_control(MSSndCard *card, MSSndCardControlElem e){
728 WinSndCard *d=(WinSndCard*)card->data;
732 static void winsndcard_init(MSSndCard *card){
733 WinSndCard *c=(WinSndCard *)ms_new(WinSndCard,1);
738 static void winsndcard_uninit(MSSndCard *card){
742 static void winsndcard_detect(MSSndCardManager *m);
743 static MSSndCard *winsndcard_dup(MSSndCard *obj);
744 static void winsndcard_unload(MSSndCardManager *m);
746 MSSndCardDesc winsnd_card_desc={
750 winsndcard_set_level,
751 winsndcard_get_level,
752 winsndcard_set_source,
753 winsndcard_set_control,
754 winsndcard_get_control,
762 static MSSndCard *winsndcard_dup(MSSndCard *obj){
763 MSSndCard *card=ms_snd_card_new(&winsnd_card_desc);
764 card->name=ms_strdup(obj->name);
765 card->data=ms_new(WinSndCard,1);
766 memcpy(card->data,obj->data,sizeof(WinSndCard));
770 static MSSndCard *winsndcard_new(const char *name, int in_dev, int out_dev, unsigned cap){
771 MSSndCard *card=ms_snd_card_new(&winsnd_card_desc);
772 WinSndCard *d=(WinSndCard*)card->data;
773 card->name=ms_strdup(name);
775 d->out_devid=out_dev;
776 card->capabilities=cap;
780 static void add_or_update_card(MSSndCardManager *m, const char *name, int indev, int outdev, unsigned int capability){
782 const MSList *elem=ms_snd_card_manager_get_list(m);
783 for(;elem!=NULL;elem=elem->next){
784 card=(MSSndCard*)elem->data;
785 if (strcmp(card->desc->driver_type, winsnd_card_desc.driver_type)==0
786 && strcmp(card->name,name)==0){
787 /*update already entered card */
788 WinSndCard *d=(WinSndCard*)card->data;
789 card->capabilities|=capability;
798 /* add this new card:*/
799 ms_snd_card_manager_add_card(m,winsndcard_new(name,indev,outdev,capability));
803 static void _winsndcard_detect(MSSndCardManager *m){
804 MMRESULT mr = NOERROR;
805 unsigned int nOutDevices = waveOutGetNumDevs ();
806 unsigned int nInDevices = waveInGetNumDevs ();
809 if (nOutDevices>nInDevices)
810 nInDevices = nOutDevices;
812 for (item = 0; item < nInDevices; item++){
816 mr = waveInGetDevCaps (item, &incaps, sizeof (WAVEINCAPS));
817 if (mr == MMSYSERR_NOERROR)
819 #if defined(_WIN32_WCE)
821 snprintf(card, sizeof(card), "Input card %i", item);
822 add_or_update_card(m,card,item,-1,MS_SND_CARD_CAP_CAPTURE);
823 /* _tprintf(L"new card: %s", incaps.szPname); */
826 WideCharToMultiByte(CP_UTF8,0,incaps.szPname,-1,szName,256,0,0);
827 add_or_update_card(m,szName,item,-1,MS_SND_CARD_CAP_CAPTURE);
830 mr = waveOutGetDevCaps (item, &outcaps, sizeof (WAVEOUTCAPS));
831 if (mr == MMSYSERR_NOERROR)
833 #if defined(_WIN32_WCE)
835 snprintf(card, sizeof(card), "Output card %i", item);
836 add_or_update_card(m,card,-1,item,MS_SND_CARD_CAP_PLAYBACK);
837 /* _tprintf(L"new card: %s", outcaps.szPname); */
840 WideCharToMultiByte(CP_UTF8,0,outcaps.szPname,-1,szName,256,0,0);
841 add_or_update_card(m,szName,-1,item,MS_SND_CARD_CAP_PLAYBACK);
847 static void deactivate_removed_cards(MSSndCardManager *m){
849 const MSList *elem=ms_snd_card_manager_get_list(m);
850 for(;elem!=NULL;elem=elem->next){
851 card=(MSSndCard*)elem->data;
852 if (strcmp(card->desc->driver_type, winsnd_card_desc.driver_type)==0){
853 /*mark all cards as potentially removed, detect will check them immediately after */
854 WinSndCard *d=(WinSndCard*)card->data;
855 if (d->removed) card->capabilities=0;
860 static void mark_as_removed(MSSndCardManager *m){
862 const MSList *elem=ms_snd_card_manager_get_list(m);
863 for(;elem!=NULL;elem=elem->next){
864 card=(MSSndCard*)elem->data;
865 if (strcmp(card->desc->driver_type, winsnd_card_desc.driver_type)==0){
866 /*mark all cards as potentially removed, detect will check them immediately after */
867 WinSndCard *d=(WinSndCard*)card->data;
873 static ms_thread_t poller_thread=NULL;
874 static bool_t poller_running=TRUE;
876 static void * new_device_polling_thread(void *ignore){
878 /*check for new devices every 5 seconds*/
879 while(poller_running){
882 m=ms_snd_card_manager_get();
885 _winsndcard_detect(m);
886 deactivate_removed_cards(m);
892 static void stop_poller(){
893 poller_running=FALSE;
894 ms_thread_join(poller_thread,NULL);
898 static void winsndcard_unload(MSSndCardManager *m){
902 static void winsndcard_detect(MSSndCardManager *m){
903 _winsndcard_detect(m);
904 if (poller_thread==NULL)
905 ms_thread_create(&poller_thread,NULL,new_device_polling_thread,NULL);
908 typedef struct WinSnd{
913 WAVEHDR hdrs_read[WINSND_NBUFS];
914 WAVEHDR hdrs_write[WINSND_OUT_NBUFS];
918 unsigned int nbufs_playing;
923 int32_t stat_notplayed;
925 int32_t stat_minimumbuffer;
928 #ifndef DISABLE_SPEEX
929 SpeexPreprocessState *pst;
933 int workaround; /* workaround for opticon audio device */
936 static void winsnd_apply_settings(WinSnd *d){
937 d->wfx.nBlockAlign=d->wfx.nChannels*d->wfx.wBitsPerSample/8;
938 d->wfx.nAvgBytesPerSec=d->wfx.nSamplesPerSec*d->wfx.nBlockAlign;
942 /*#define _TRUE_TIME*/
944 static uint64_t winsnd_get_cur_time( void *data){
945 WinSnd *d=(WinSnd*)data;
946 uint64_t curtime=(d->bytes_read*1000)/(uint64_t)d->wfx.nAvgBytesPerSec;
947 /* ms_debug("winsnd_get_cur_time: bytes_read=%u return %lu\n",d->bytes_read,(unsigned long)curtime); */
953 static void winsnd_init(MSFilter *f){
954 WinSnd *d=(WinSnd *)ms_new0(WinSnd,1);
955 d->wfx.wFormatTag = WAVE_FORMAT_PCM;
957 d->wfx.nAvgBytesPerSec = 16000;
958 d->wfx.nBlockAlign = 2;
959 d->wfx.nChannels = 1;
960 d->wfx.nSamplesPerSec = 8000;
961 d->wfx.wBitsPerSample = 16;
964 #ifndef DISABLE_SPEEX
970 ms_mutex_init(&d->mutex,NULL);
976 d->stat_minimumbuffer=WINSND_MINIMUMBUFFER;
979 static void winsnd_uninit(MSFilter *f){
980 WinSnd *d=(WinSnd*)f->data;
982 flushq(&d->write_rq,0);
983 #ifndef DISABLE_SPEEX
985 speex_preprocess_state_destroy(d->pst);
991 ms_mutex_destroy(&d->mutex);
995 static void add_input_buffer(WinSnd *d, WAVEHDR *hdr, int buflen){
996 mblk_t *m=allocb(buflen,0);
998 memset(hdr,0,sizeof(*hdr));
999 if (buflen==0) ms_error("add_input_buffer: buflen=0 !");
1000 hdr->lpData=(LPSTR)m->b_wptr;
1001 hdr->dwBufferLength=buflen;
1003 hdr->dwUser = (DWORD)m;
1004 mr = waveInPrepareHeader (d->indev,hdr,sizeof(*hdr));
1005 if (mr != MMSYSERR_NOERROR){
1006 ms_error("waveInPrepareHeader() error");
1009 mr=waveInAddBuffer(d->indev,hdr,sizeof(*hdr));
1010 if (mr != MMSYSERR_NOERROR){
1011 ms_error("waveInAddBuffer() error");
1016 static void CALLBACK
1017 read_callback (HWAVEIN waveindev, UINT uMsg, DWORD dwInstance, DWORD dwParam1,
1020 WAVEHDR *wHdr=(WAVEHDR *) dwParam1;
1021 MSFilter *f=(MSFilter *)dwInstance;
1022 WinSnd *d=(WinSnd*)f->data;
1027 ms_debug("read_callback : WIM_OPEN");
1030 ms_debug("read_callback : WIM_CLOSE");
1033 bsize=wHdr->dwBytesRecorded;
1036 if (d->running==TRUE) /* avoid adding buffer back when calling waveInReset */
1039 mr=waveInAddBuffer(d->indev,wHdr,sizeof(*wHdr));
1040 if (mr != MMSYSERR_NOERROR){
1041 ms_error("waveInAddBuffer() error");
1044 ms_warning("read_callback : EMPTY DATA, WIM_DATA (%p,%i)",wHdr,bsize);
1046 m=(mblk_t*)wHdr->dwUser;
1053 /* ms_warning("read_callback : WIM_DATA (%p,%i)",wHdr,bsize); */
1054 m=(mblk_t*)wHdr->dwUser;
1057 ms_mutex_lock(&d->mutex);
1059 ms_mutex_unlock(&d->mutex);
1060 d->bytes_read+=wHdr->dwBufferLength;
1064 if (f->ticker->TimeEvent!=NULL)
1065 SetEvent(f->ticker->TimeEvent);
1072 static void winsnd_read_preprocess(MSFilter *f){
1073 WinSnd *d=(WinSnd*)f->data;
1081 d->stat_notplayed=0;
1082 d->stat_minimumbuffer=WINSND_MINIMUMBUFFER;
1084 winsnd_apply_settings(d);
1085 /* Init Microphone device */
1086 dwFlag = CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT;
1087 mr = waveInOpen (&d->indev, d->dev_id, &d->wfx,
1088 (DWORD) read_callback, (DWORD)f, dwFlag);
1089 if (mr != MMSYSERR_NOERROR)
1091 ms_error("Failed to prepare windows sound device. (waveInOpen:0x%i)", mr);
1092 if (d->dev_id != WAVE_MAPPER)
1093 dwFlag = WAVE_MAPPED | CALLBACK_FUNCTION;
1094 mr = waveInOpen (&d->indev, d->dev_id, &d->wfx,
1095 (DWORD) read_callback, (DWORD)f, dwFlag);
1097 if (mr != MMSYSERR_NOERROR)
1099 ms_error("Failed to prepare windows sound device. (waveInOpen:0x%i)", mr);
1100 mr = waveInOpen (&d->indev, WAVE_MAPPER, &d->wfx,
1101 (DWORD) read_callback, (DWORD)f, CALLBACK_FUNCTION);
1102 if (mr != MMSYSERR_NOERROR)
1105 ms_error("Failed to prepare windows sound device. (waveInOpen:0x%i)", mr);
1110 ms_mutex_lock(&f->ticker->lock);
1111 ms_ticker_set_time_func(f->ticker,winsnd_get_cur_time,d);
1112 ms_mutex_unlock(&f->ticker->lock);
1115 bsize=WINSND_NSAMPLES*d->wfx.nAvgBytesPerSec/8000;
1116 ms_debug("Using input buffers of %i bytes",bsize);
1117 for(i=0;i<WINSND_NBUFS;++i){
1118 WAVEHDR *hdr=&d->hdrs_read[i];
1119 add_input_buffer(d,hdr,bsize);
1122 mr=waveInStart(d->indev);
1123 if (mr != MMSYSERR_NOERROR){
1124 ms_error("waveInStart() error");
1126 ms_mutex_lock(&f->ticker->lock);
1127 ms_ticker_set_time_func(f->ticker,NULL,NULL);
1128 ms_mutex_unlock(&f->ticker->lock);
1134 static void winsnd_read_postprocess(MSFilter *f){
1135 WinSnd *d=(WinSnd*)f->data;
1139 ms_mutex_lock(&f->ticker->lock);
1140 ms_ticker_set_time_func(f->ticker,NULL,NULL);
1141 ms_mutex_unlock(&f->ticker->lock);
1144 mr=waveInStop(d->indev);
1145 if (mr != MMSYSERR_NOERROR){
1146 ms_error("waveInStop() error");
1149 mr=waveInReset(d->indev);
1150 if (mr != MMSYSERR_NOERROR){
1151 ms_error("waveInReset() error");
1154 for(i=0;i<WINSND_NBUFS;++i){
1155 WAVEHDR *hdr=&d->hdrs_read[i];
1156 if (hdr->dwFlags & WHDR_PREPARED)
1158 mr = waveInUnprepareHeader(d->indev,hdr,sizeof (*hdr));
1159 if (mr != MMSYSERR_NOERROR){
1160 ms_error("waveInUnPrepareHeader() error");
1164 mr = waveInClose(d->indev);
1165 if (mr != MMSYSERR_NOERROR){
1166 ms_error("waveInClose() error");
1170 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);
1174 static void winsnd_read_process(MSFilter *f){
1175 WinSnd *d=(WinSnd*)f->data;
1178 ms_mutex_lock(&d->mutex);
1179 while((m=getq(&d->rq))!=NULL){
1180 ms_queue_put(f->outputs[0],m);
1182 ms_mutex_unlock(&d->mutex);
1183 for(i=0;i<WINSND_NBUFS;++i){
1184 WAVEHDR *hdr=&d->hdrs_read[i];
1185 if (hdr->dwUser==0) {
1187 mr=waveInUnprepareHeader(d->indev,hdr,sizeof(*hdr));
1188 if (mr!=MMSYSERR_NOERROR)
1189 ms_warning("winsnd_read_process: Fail to unprepare header!");
1190 add_input_buffer(d,hdr,hdr->dwBufferLength);
1195 static void CALLBACK
1196 write_callback(HWAVEOUT outdev, UINT uMsg, DWORD dwInstance,
1197 DWORD dwParam1, DWORD dwParam2)
1199 WAVEHDR *hdr=(WAVEHDR *) dwParam1;
1200 WinSnd *d=(WinSnd*)dwInstance;
1210 if (d->stat_output==0)
1212 d->stat_input=1; /* reset */
1213 d->stat_notplayed=0;
1220 static void winsnd_write_preprocess(MSFilter *f){
1221 WinSnd *d=(WinSnd*)f->data;
1228 d->stat_notplayed=0;
1229 d->stat_minimumbuffer=WINSND_MINIMUMBUFFER;
1231 winsnd_apply_settings(d);
1232 /* Init Microphone device */
1233 dwFlag = CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT;
1234 mr = waveOutOpen (&d->outdev, d->dev_id, &d->wfx,
1235 (DWORD) write_callback, (DWORD)d, dwFlag);
1236 if (mr != MMSYSERR_NOERROR)
1238 ms_error("Failed to open windows sound device %i. (waveOutOpen:0x%i)",d->dev_id, mr);
1239 if (d->dev_id != WAVE_MAPPER)
1240 dwFlag = WAVE_MAPPED | CALLBACK_FUNCTION;
1241 mr = waveOutOpen (&d->outdev, d->dev_id, &d->wfx,
1242 (DWORD) write_callback, (DWORD)d, dwFlag);
1244 if (mr != MMSYSERR_NOERROR)
1246 ms_error("Failed to open windows sound device %i. (waveOutOpen:0x%i)",d->dev_id, mr);
1247 mr = waveOutOpen (&d->outdev, WAVE_MAPPER, &d->wfx,
1248 (DWORD) write_callback, (DWORD)d, CALLBACK_FUNCTION);
1249 if (mr != MMSYSERR_NOERROR)
1251 ms_error("Failed to open windows sound device %i. (waveOutOpen:0x%i)",d->dev_id, mr);
1256 for(i=0;i<WINSND_OUT_NBUFS;++i){
1257 WAVEHDR *hdr=&d->hdrs_write[i];
1263 static void winsnd_write_postprocess(MSFilter *f){
1264 WinSnd *d=(WinSnd*)f->data;
1267 if (d->outdev==NULL) return;
1268 mr=waveOutReset(d->outdev);
1269 if (mr != MMSYSERR_NOERROR){
1270 ms_error("waveOutReset() error");
1273 for(i=0;i<WINSND_OUT_NBUFS;++i){
1274 WAVEHDR *hdr=&d->hdrs_write[i];
1276 if (hdr->dwFlags & WHDR_DONE){
1277 mr=waveOutUnprepareHeader(d->outdev,hdr,sizeof(*hdr));
1278 if (mr != MMSYSERR_NOERROR){
1279 ms_error("waveOutUnprepareHeader error");
1281 old=(mblk_t*)hdr->dwUser;
1282 if (old) freemsg(old);
1286 mr=waveOutClose(d->outdev);
1287 if (mr != MMSYSERR_NOERROR){
1288 ms_error("waveOutClose() error");
1291 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);
1292 flushq(&d->write_rq,0);
1296 #ifndef DISABLE_SPEEX
1298 speex_preprocess_state_destroy(d->pst);
1300 d->pst_frame_size=0;
1304 static void winsnd_write_process(MSFilter *f){
1305 WinSnd *d=(WinSnd*)f->data;
1310 int possible_size=0;
1312 if (d->outdev==NULL) {
1313 ms_queue_flush(f->inputs[0]);
1317 while((m=ms_queue_get(f->inputs[0]))!=NULL){
1318 possible_size = msgdsize(m);
1319 #ifndef DISABLE_SPEEX
1320 if (d->pst_frame_size==0)
1322 d->pst_frame_size=possible_size;
1324 d->pst = speex_preprocess_state_init(d->pst_frame_size/2, d->wfx.nSamplesPerSec);
1328 speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_VAD, &i);
1330 speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_DENOISE, &i);
1332 speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_AGC, &i);
1334 speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_AGC_LEVEL, &f);
1336 speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_DEREVERB, &i);
1341 putq(&d->write_rq,m);
1345 /* too many sound card are crappy on windows... */
1346 d->stat_minimumbuffer=15;
1347 if (d->wfx.nSamplesPerSec>=32000) /* better results for high rates */
1348 d->stat_minimumbuffer=8;
1351 if (d->wfx.nSamplesPerSec>=32000) /* better results for high rates */
1353 if (d->nbufs_playing+d->write_rq.q_mcount<4)
1360 if (d->nbufs_playing+d->write_rq.q_mcount<7)
1365 #if defined(WCE_OPTICON_WORKAROUND)
1366 if (d->workaround==0)
1369 Sleep(WCE_OPTICON_WORKAROUND);
1373 while((m=peekq(&d->write_rq))!=NULL){
1375 #ifndef DISABLE_SPEEX
1377 if (d->pst!=NULL && msgdsize(m)==d->pst_frame_size && d->pst_frame_size<=4096)
1380 memcpy(tmp, m->b_rptr, msgdsize(m));
1381 vad = speex_preprocess(d->pst, (short*)tmp, NULL);
1388 missing = 10 - d->write_rq.q_mcount - d->nbufs_playing;
1389 if (d->wfx.nSamplesPerSec>=32000) /* better results for high rates */
1390 missing = 6 - d->write_rq.q_mcount - d->nbufs_playing;
1392 ms_message("WINSND trouble: inserting %i silence", missing);
1396 putq(&d->write_rq,old);
1407 missing = 10 - d->write_rq.q_mcount - d->nbufs_playing;
1408 if (d->wfx.nSamplesPerSec>=32000) /* better results for high rates */
1409 missing = 6 - d->write_rq.q_mcount - d->nbufs_playing;
1410 ms_message("WINSND trouble: inserting %i silence", missing);
1414 putq(&d->write_rq,old);
1421 for(i=0;i<d->stat_minimumbuffer;++i){
1422 WAVEHDR *hdr=&d->hdrs_write[i];
1423 if (hdr->dwFlags & WHDR_DONE){
1424 old=(mblk_t*)hdr->dwUser;
1425 mr=waveOutUnprepareHeader(d->outdev,hdr,sizeof(*hdr));
1426 if (mr != MMSYSERR_NOERROR){
1427 ms_error("waveOutUnprepareHeader error");
1432 if (hdr->dwUser==0){
1433 hdr->lpData=(LPSTR)m->b_rptr;
1434 hdr->dwBufferLength=msgdsize(m);
1436 hdr->dwUser = (DWORD)m;
1437 mr = waveOutPrepareHeader(d->outdev,hdr,sizeof(*hdr));
1438 if (mr != MMSYSERR_NOERROR){
1439 ms_error("waveOutPrepareHeader() error");
1443 d->stat_notplayed++;
1446 mr=waveOutWrite(d->outdev,hdr,sizeof(*hdr));
1447 if (mr != MMSYSERR_NOERROR){
1448 ms_error("waveOutWrite() error");
1452 d->stat_notplayed++;
1457 /* ms_debug("waveOutWrite() done"); */
1462 if (i==d->stat_minimumbuffer){
1463 /* ms_error("winsnd_write_process: All buffers are busy."); */
1464 #ifndef DISABLE_SPEEX
1467 /* initial behavior (detection in process?) */
1471 d->stat_notplayed++;
1479 ms_message("WINSND trouble: silence removed");
1481 d->stat_notplayed++;
1488 d->stat_notplayed++;
1496 static int get_rate(MSFilter *f, void *arg){
1497 WinSnd *d=(WinSnd*)f->data;
1498 *((int*)arg)=d->wfx.nSamplesPerSec;
1502 static int set_rate(MSFilter *f, void *arg){
1503 WinSnd *d=(WinSnd*)f->data;
1504 d->wfx.nSamplesPerSec=*((int*)arg);
1505 d->wfx.nSamplesPerSec=44100;
1509 static int set_nchannels(MSFilter *f, void *arg){
1510 WinSnd *d=(WinSnd*)f->data;
1511 d->wfx.nChannels=*((int*)arg);
1515 static int winsnd_get_stat_input(MSFilter *f, void *arg){
1516 WinSnd *d=(WinSnd*)f->data;
1517 return d->stat_input;
1520 static int winsnd_get_stat_ouptut(MSFilter *f, void *arg){
1521 WinSnd *d=(WinSnd*)f->data;
1523 return d->stat_output;
1526 static int winsnd_get_stat_discarded(MSFilter *f, void *arg){
1527 WinSnd *d=(WinSnd*)f->data;
1529 return d->stat_notplayed;
1532 static MSFilterMethod winsnd_methods[]={
1533 { MS_FILTER_GET_SAMPLE_RATE , get_rate },
1534 { MS_FILTER_SET_SAMPLE_RATE , set_rate },
1535 { MS_FILTER_SET_NCHANNELS , set_nchannels },
1536 { MS_FILTER_GET_STAT_INPUT, winsnd_get_stat_input },
1537 { MS_FILTER_GET_STAT_OUTPUT, winsnd_get_stat_ouptut },
1538 { MS_FILTER_GET_STAT_DISCARDED, winsnd_get_stat_discarded },
1542 MSFilterDesc winsnd_read_desc={
1545 "MME capture filter for Windows",
1551 winsnd_read_preprocess,
1552 winsnd_read_process,
1553 winsnd_read_postprocess,
1559 MSFilterDesc winsnd_write_desc={
1562 "MME playback filter for Windows",
1568 winsnd_write_preprocess,
1569 winsnd_write_process,
1570 winsnd_write_postprocess,
1575 MSFilter *ms_winsnd_read_new(MSSndCard *card){
1576 MSFilter *f=ms_filter_new_from_desc(&winsnd_read_desc);
1577 WinSndCard *wc=(WinSndCard*)card->data;
1578 WinSnd *d=(WinSnd*)f->data;
1579 d->dev_id=wc->in_devid;
1584 MSFilter *ms_winsnd_write_new(MSSndCard *card){
1585 MSFilter *f=ms_filter_new_from_desc(&winsnd_write_desc);
1586 WinSndCard *wc=(WinSndCard*)card->data;
1587 WinSnd *d=(WinSnd*)f->data;
1588 d->dev_id=wc->out_devid;
1592 MS_FILTER_DESC_EXPORT(winsnd_read_desc)
1593 MS_FILTER_DESC_EXPORT(winsnd_write_desc)