source: mediastreamer2/linphone/mediastreamer2/src/winsnd2.c @ 769:6660c4f64de4

Last change on this file since 769:6660c4f64de4 was 769:6660c4f64de4, checked in by aymeric <aymeric@…>, 4 years ago

fix time overflow for long calls.

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

  • Property exe set to *
File size: 45.0 KB
Line 
1/*
2mediastreamer2 library - modular sound and video processing and streaming
3Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18*/
19
20#ifndef UNICODE
21#define UNICODE
22#endif
23
24#include "mediastreamer2/mssndcard.h"
25#include "mediastreamer2/msfilter.h"
26#include "mediastreamer2/msticker.h"
27
28#include <mmsystem.h>
29#ifdef _MSC_VER
30#include <mmreg.h>
31#endif
32#include <msacm.h>
33
34#if defined(_WIN32_WCE)
35/*#define DISABLE_SPEEX */
36/*#define WCE_OPTICON_WORKAROUND 1000 */
37#endif
38#ifndef DISABLE_SPEEX
39#include <speex/speex_preprocess.h>
40#endif
41
42#define WINSND_NBUFS 10
43#define WINSND_OUT_NBUFS 20
44#define WINSND_NSAMPLES 160
45#define WINSND_MINIMUMBUFFER 5
46
47static MSFilter *ms_winsnd_read_new(MSSndCard *card);
48static MSFilter *ms_winsnd_write_new(MSSndCard *card);
49
50typedef struct WinSndCard{
51        int in_devid;
52        int out_devid;
53        int removed;
54}WinSndCard;
55
56static void winsndcard_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent){
57        WinSndCard *d=(WinSndCard*)card->data;
58
59        UINT uMixerID;
60        DWORD dwMixerHandle;
61        MIXERLINE MixerLine;
62        MIXERLINE Line;
63        UINT uLineIndex;
64
65        MIXERLINECONTROLS mlc = {0};
66        MIXERCONTROL mc = {0};
67        MIXERCONTROLDETAILS mcd = {0};
68        MIXERCONTROLDETAILS_UNSIGNED mcdu = {0};
69
70        MMRESULT mr = MMSYSERR_NOERROR;
71        DWORD dwVolume = ((0xFFFF) * percent) / 100;
72       
73        WORD wLeftVol, wRightVol;
74        DWORD dwNewVol;
75        wLeftVol = LOWORD(dwVolume); // get higher WORD
76        wRightVol = LOWORD(dwVolume); // get lower WORD
77
78        dwNewVol = MAKELONG(wLeftVol, wRightVol);
79
80        switch(e){
81                case MS_SND_CARD_PLAYBACK:
82                case MS_SND_CARD_MASTER:
83                        {
84                                mr = mixerGetID( (HMIXEROBJ)d->out_devid, &uMixerID, MIXER_OBJECTF_WAVEOUT );
85                                if ( mr != MMSYSERR_NOERROR )
86                                {
87                                        ms_error("winsndcard_set_level: mixerGetID failed. (0x%x)", mr);
88                                        return;
89                                }
90                                mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
91                                if ( mr != MMSYSERR_NOERROR )
92                                {
93                                        mixerClose( (HMIXER)dwMixerHandle );
94                                        ms_error("winsndcard_set_level: mixerOpen failed. (0x%x)", mr);
95                                        return;
96                                }
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;
101                                else
102                                        MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
103                                mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE );
104                                if ( mr != MMSYSERR_NOERROR )
105                                {
106                                        mixerClose( (HMIXER)dwMixerHandle );
107                                        ms_error("winsndcard_set_level: mixerGetLineInfo failed. (0x%x)", mr);
108                                        return;
109                                }
110
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); */
114
115                                mlc.cbStruct = sizeof(MIXERLINECONTROLS);
116                                mlc.dwLineID = MixerLine.dwLineID;
117                                mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
118                                mlc.cControls = 1;
119                                mlc.pamxctrl = &mc;
120                                mlc.cbmxctrl = sizeof(MIXERCONTROL);
121                                mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle, 
122                                        &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
123
124
125                                mcdu.dwValue = 65535*percent/100; /* the volume is a number between 0 and 65535 */
126
127                                mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
128                                mcd.hwndOwner = 0;
129                                mcd.dwControlID = mc.dwControlID;
130                                mcd.paDetails = &mcdu;
131                                mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
132                                mcd.cChannels = 1;
133                                mr = mixerSetControlDetails((HMIXEROBJ)dwMixerHandle, 
134                                        &mcd, MIXER_SETCONTROLDETAILSF_VALUE);
135
136                                if (mr != MMSYSERR_NOERROR)
137                                {
138                                        ms_error("winsndcard_set_level: mixerSetControlDetails failed. (0x%x)", mr);
139                                        return;
140                                }
141                        }
142                        break;
143                case MS_SND_CARD_CAPTURE:
144                        mr = mixerGetID( (HMIXEROBJ)d->in_devid, &uMixerID, MIXER_OBJECTF_WAVEIN );
145                        if ( mr != MMSYSERR_NOERROR )
146                        {
147                                ms_error("winsndcard_set_level: mixerGetID failed. (0x%x)", mr);
148                                return;
149                        }
150                        mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
151                        if ( mr != MMSYSERR_NOERROR )
152                        {
153                                mixerClose( (HMIXER)dwMixerHandle );
154                                ms_error("winsndcard_set_level: mixerGetLineInfo failed. (0x%x)", mr);
155                                return;
156                        }
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 )
162                        {
163                                mixerClose( (HMIXER)dwMixerHandle );
164                                ms_error("winsndcard_set_level: mixerGetLineInfo failed. (0x%x)", mr);
165                                return;
166                        }
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); */
170
171                        mlc.cbStruct = sizeof(MIXERLINECONTROLS);
172                        mlc.dwLineID = MixerLine.dwLineID;
173                        mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
174                        mlc.cControls = 1;
175                        mlc.pamxctrl = &mc;
176                        mlc.cbmxctrl = sizeof(MIXERCONTROL);
177                        mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle, 
178                                &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
179
180                        if (mr == MMSYSERR_NOERROR)
181                        {
182                                mcdu.dwValue = 65535*percent/100; /* the volume is a number between 0 and 65535 */
183
184                                mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
185                                mcd.hwndOwner = 0;
186                                mcd.dwControlID = mc.dwControlID;
187                                mcd.paDetails = &mcdu;
188                                mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
189                                mcd.cChannels = 1;
190                                mr = mixerSetControlDetails((HMIXEROBJ)dwMixerHandle, 
191                                        &mcd, MIXER_SETCONTROLDETAILSF_VALUE);
192
193                                if (mr == MMSYSERR_NOERROR)
194                                {
195                                        return;
196                                }
197                                ms_error("winsndcard_set_level: mixerSetControlDetails failed. (0x%x)", mr);
198                                ms_warning("winsndcard_set_level: control the SRC_MICROPHONE instead");
199                        }
200                        else
201                        {
202                                ms_error("winsndcard_set_level: mixerGetLineControls failed. (0x%x)", mr);
203                                ms_warning("winsndcard_set_level: control the SRC_MICROPHONE instead");
204                        }
205
206                        /* In case capture doesn't work: use the SRC_MICROPHONE volume */
207
208                        for (uLineIndex = 0; uLineIndex < MixerLine.cConnections; uLineIndex++)
209                        {
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 )
216                                {
217                                        mixerClose( (HMIXER)dwMixerHandle );
218                                        ms_error("winsndcard_set_level: mixerGetLineInfo failed. (0x%x)", mr);
219                                        return;
220                                }
221
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); */
226
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 )
233                                {
234                                        mixerClose( (HMIXER)dwMixerHandle );
235                                        ms_error("winsndcard_set_level: mixerGetLineInfo failed. (0x%x)", mr);
236                                        return;
237                                }
238
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); */
243
244                                if (MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE == Line.dwComponentType) 
245                                {
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) 
254                                                                cChannels = 1; 
255                                                        pUnsigned = 
256                                                                (LPMIXERCONTROLDETAILS_UNSIGNED) 
257                                                                malloc(cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
258
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;
265
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); 
272                                                        free(pmxctrl); 
273                                                        free(pUnsigned); 
274                                        } 
275                                        else 
276                                                free(pmxctrl); 
277                                }
278                        }
279                        mixerClose( (HMIXER)dwMixerHandle );
280                        if (mr != MMSYSERR_NOERROR)
281                        {
282                                ms_error("winsndcard_set_level: mixerClose failed. (0x%x)", mr);
283                                return;
284                        }
285                        break;
286                default:
287                        ms_warning("winsnd_card_set_level: unsupported command.");
288        }
289}
290
291static int winsndcard_get_level(MSSndCard *card, MSSndCardMixerElem e){
292        WinSndCard *d=(WinSndCard*)card->data;
293
294        UINT uMixerID;
295        DWORD dwMixerHandle;
296        MIXERLINE MixerLine;
297        MIXERLINE Line;
298        UINT uLineIndex;
299
300        MIXERLINECONTROLS mlc = {0};
301        MIXERCONTROL mc = {0};
302        MIXERCONTROLDETAILS mcd = {0};
303        MIXERCONTROLDETAILS_UNSIGNED mcdu = {0};
304
305        MMRESULT mr = MMSYSERR_NOERROR;
306        int percent;
307
308        switch(e){
309                case MS_SND_CARD_MASTER:
310                case MS_SND_CARD_PLAYBACK:
311                        {
312                                mr = mixerGetID( (HMIXEROBJ)d->out_devid, &uMixerID, MIXER_OBJECTF_WAVEOUT );
313                                if ( mr != MMSYSERR_NOERROR )
314                                {
315                                        ms_error("winsndcard_get_level: mixerGetID failed. (0x%x)", mr);
316                                        return -1;
317                                }
318                                mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
319                                if ( mr != MMSYSERR_NOERROR )
320                                {
321                                        mixerClose( (HMIXER)dwMixerHandle );
322                                        ms_error("winsndcard_get_level: mixerOpen failed. (0x%x)", mr);
323                                        return -1;
324                                }
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;
329                                else
330                                        MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
331                                mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE );
332                                if ( mr != MMSYSERR_NOERROR )
333                                {
334                                        mixerClose( (HMIXER)dwMixerHandle );
335                                        ms_error("winsndcard_get_level: mixerGetLineInfo failed. (0x%x)", mr);
336                                        return -1;
337                                }
338
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); */
342
343                                mlc.cbStruct = sizeof(MIXERLINECONTROLS);
344                                mlc.dwLineID = MixerLine.dwLineID;
345                                mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
346                                mlc.cControls = 1;
347                                mlc.pamxctrl = &mc;
348                                mlc.cbmxctrl = sizeof(MIXERCONTROL);
349                                mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle, 
350                                        &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
351                                if (mr != MMSYSERR_NOERROR)
352                                {
353                                        ms_error("winsndcard_get_level: mixerGetLineControls failed. (0x%x)", mr);
354                                        return -1;
355                                }
356
357                                mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
358                                mcd.hwndOwner = 0;
359                                mcd.dwControlID = mc.dwControlID;
360                                mcd.paDetails = &mcdu;
361                                mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
362                                mcd.cChannels = 1;
363                                mr = mixerGetControlDetails((HMIXEROBJ)dwMixerHandle, &mcd, 
364                                        MIXER_SETCONTROLDETAILSF_VALUE); 
365                                percent = (mcdu.dwValue *100) / (mc.Bounds.dwMaximum);
366
367                                if (mr != MMSYSERR_NOERROR)
368                                {
369                                        ms_error("winsndcard_get_level: mixerGetControlDetails failed. (0x%x)", mr);
370                                        return -1;
371                                }
372                                return percent;
373                        }
374                        break;
375                case MS_SND_CARD_CAPTURE:
376                        mr = mixerGetID( (HMIXEROBJ)d->in_devid, &uMixerID, MIXER_OBJECTF_WAVEIN );
377                        if ( mr != MMSYSERR_NOERROR )
378                        {
379                                ms_error("winsndcard_get_level: mixerGetID failed. (0x%x)", mr);
380                                return -1;
381                        }
382                        mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
383                        if ( mr != MMSYSERR_NOERROR )
384                        {
385                                mixerClose( (HMIXER)dwMixerHandle );
386                                ms_error("winsndcard_get_level: mixerOpen failed. (0x%x)", mr);
387                                return -1;
388                        }
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 )
394                        {
395                                mixerClose( (HMIXER)dwMixerHandle );
396                                ms_error("winsndcard_get_level: mixerGetLineInfo failed. (0x%x)", mr);
397                                return -1;
398                        }
399
400                        mlc.cbStruct = sizeof(MIXERLINECONTROLS);
401                        mlc.dwLineID = MixerLine.dwLineID;
402                        mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
403                        mlc.cControls = 1;
404                        mlc.pamxctrl = &mc;
405                        mlc.cbmxctrl = sizeof(MIXERCONTROL);
406                        mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle, 
407                                &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
408                        if (mr == MMSYSERR_NOERROR)
409                        {
410                                mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
411                                mcd.hwndOwner = 0;
412                                mcd.dwControlID = mc.dwControlID;
413                                mcd.paDetails = &mcdu;
414                                mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
415                                mcd.cChannels = 1;
416                                mr = mixerGetControlDetails((HMIXEROBJ)dwMixerHandle, &mcd, 
417                                        MIXER_SETCONTROLDETAILSF_VALUE); 
418                                percent = (mcdu.dwValue *100) / (mc.Bounds.dwMaximum);
419
420                                if (mr == MMSYSERR_NOERROR)
421                                {
422                                        return percent;
423                                }
424                                ms_error("winsndcard_get_level: mixerGetControlDetails failed. (0x%x)", mr);
425                                ms_warning("winsndcard_get_level: control the SRC_MICROPHONE instead");
426                        }
427                        else
428                        {
429                                ms_error("winsndcard_get_level: mixerGetLineControls failed. (0x%x)", mr);
430                                ms_warning("winsndcard_get_level: control the SRC_MICROPHONE instead");
431                        }
432       
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); */
436
437                        for (uLineIndex = 0; uLineIndex < MixerLine.cConnections; uLineIndex++)
438                        {
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 )
445                                {
446                                        mixerClose( (HMIXER)dwMixerHandle );
447                                        ms_error("winsndcard_get_level: mixerGetLineInfo failed. (0x%x)", mr);
448                                        return -1;
449                                }
450
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); */
455
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 )
462                                {
463                                        mixerClose( (HMIXER)dwMixerHandle );
464                                        ms_error("winsndcard_get_level: mixerGetLineInfo failed. (0x%x)", mr);
465                                        return -1;
466                                }
467
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); */
472
473                                if (MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE == Line.dwComponentType) 
474                                {
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) 
483                                                                cChannels = 1; 
484                                                        pUnsigned = 
485                                                                (LPMIXERCONTROLDETAILS_UNSIGNED) 
486                                                                malloc(cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
487
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;
494
495                                                        mixerGetControlDetails((HMIXEROBJ)dwMixerHandle, &mxcd, 
496                                                                MIXER_SETCONTROLDETAILSF_VALUE); 
497                                                        percent = (pUnsigned[0].dwValue *100) / (pmxctrl->Bounds.dwMaximum);
498                                                        free(pmxctrl);
499                                                        free(pUnsigned);
500                                        } 
501                                        else 
502                                                free(pmxctrl); 
503                                }
504                        }
505                        mixerClose( (HMIXER)dwMixerHandle );
506                        if (mr != MMSYSERR_NOERROR)
507                        {
508                                ms_error("winsndcard_get_level: mixerClose failed. (0x%x)", mr);
509                                return -1;
510                        }
511                        return percent;
512                        break;
513                default:
514                        ms_warning("winsndcard_get_level: unsupported command.");
515                        return -1;
516        }
517        return -1;
518}
519
520static void winsndcard_set_source(MSSndCard *card, MSSndCardCapture source){
521
522        switch(source){
523                case MS_SND_CARD_MIC:
524                        break;
525                case MS_SND_CARD_LINE:
526                        break;
527        }       
528}
529
530static int winsndcard_set_control(MSSndCard *card, MSSndCardControlElem e, int val){
531        WinSndCard *d=(WinSndCard*)card->data;
532
533        UINT uMixerID;
534        DWORD dwMixerHandle;
535        MIXERLINE MixerLine;
536        MIXERLINE Line;
537        UINT uLineIndex;
538
539        MIXERLINECONTROLS mlc = {0};
540        MIXERCONTROL mc = {0};
541        MIXERCONTROLDETAILS mcd = {0};
542        MIXERCONTROLDETAILS_BOOLEAN bMute;
543
544        MMRESULT mr = MMSYSERR_NOERROR;
545
546        switch(e){
547                case MS_SND_CARD_CAPTURE_MUTE:
548
549                        bMute.fValue = (val>0);
550
551                        mr = mixerGetID( (HMIXEROBJ)d->in_devid, &uMixerID, MIXER_OBJECTF_WAVEIN );
552                        if ( mr != MMSYSERR_NOERROR )
553                        {
554                                ms_error("winsndcard_set_control: mixerGetID failed. (0x%x)", mr);
555                                return -1;
556                        }
557                        mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
558                        if ( mr != MMSYSERR_NOERROR )
559                        {
560                                mixerClose( (HMIXER)dwMixerHandle );
561                                ms_error("winsndcard_set_control: mixerOpen failed. (0x%x)", mr);
562                                return -1;
563                        }
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 )
569                        {
570                                mixerClose( (HMIXER)dwMixerHandle );
571                                ms_error("winsndcard_set_control: mixerGetLineInfo failed. (0x%x)", mr);
572                                return -1;
573                        }
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); */
577
578                        for (uLineIndex = 0; uLineIndex < MixerLine.cConnections; uLineIndex++)
579                        {
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 )
586                                {
587                                        mixerClose( (HMIXER)dwMixerHandle );
588                                        ms_error("winsndcard_set_control: mixerGetLineInfo failed. (0x%x)", mr);
589                                        return -1;
590                                }
591                               
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); */
596
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 )
603                                {
604                                        mixerClose( (HMIXER)dwMixerHandle );
605                                        ms_error("winsndcard_set_control: mixerGetLineInfo failed. (0x%x)", mr);
606                                        return -1;
607                                }
608
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); */
613
614                                if (MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE == Line.dwComponentType) 
615                                {
616                                        /* unmute */
617                                        /* Find a mute control, if any, of the microphone line  */
618
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;
625
626                                                if (MIXERCONTROL_CONTROLF_UNIFORM & pmxctrl->fdwControl) 
627                                                        cChannels = 1; 
628                                                pbool = (LPMIXERCONTROLDETAILS_BOOLEAN) malloc(cChannels * sizeof(
629                                                        MIXERCONTROLDETAILS_BOOLEAN));
630
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;
637
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); 
644                                                free(pmxctrl); 
645                                                free(pbool); 
646                                        } 
647                                        else 
648                                                free(pmxctrl); 
649                                }
650                        }
651                        mixerClose( (HMIXER)dwMixerHandle );
652                        if (mr != MMSYSERR_NOERROR)
653                        {
654                                ms_error("winsndcard_set_control: mixerClose failed. (0x%x)", mr);
655                                return -1;
656                        }
657                        return 0;
658
659                case MS_SND_CARD_MASTER_MUTE:
660                case MS_SND_CARD_PLAYBACK_MUTE:
661                        {
662                                bMute.fValue = (val>0);
663
664                                mr = mixerGetID( (HMIXEROBJ)d->out_devid, &uMixerID, MIXER_OBJECTF_WAVEOUT );
665                                if ( mr != MMSYSERR_NOERROR )
666                                {
667                                        ms_error("winsndcard_set_control: mixerGetID failed. (0x%x)", mr);
668                                        return -1;
669                                }
670                                mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
671                                if ( mr != MMSYSERR_NOERROR )
672                                {
673                                        mixerClose( (HMIXER)dwMixerHandle );
674                                        ms_error("winsndcard_set_control: mixerOpen failed. (0x%x)", mr);
675                                        return -1;
676                                }
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;
681                                else
682                                        MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
683                                mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE );
684                                if ( mr != MMSYSERR_NOERROR )
685                                {
686                                        mixerClose( (HMIXER)dwMixerHandle );
687                                        ms_error("winsndcard_set_control: mixerSetControlDetails failed. (0x%x)", mr);
688                                        return -1;
689                                }
690
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); */
694
695                                mlc.cbStruct = sizeof(MIXERLINECONTROLS);
696                                mlc.dwLineID = MixerLine.dwLineID;
697                                mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE; //MIXERCONTROL_CONTROLTYPE_VOLUME;
698                                mlc.cControls = 1;
699                                mlc.pamxctrl = &mc;
700                                mlc.cbmxctrl = sizeof(MIXERCONTROL);
701                                mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle, 
702                                        &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
703
704                                mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
705                                mcd.hwndOwner = 0;
706                                mcd.dwControlID = mc.dwControlID;
707                                mcd.paDetails = &bMute;
708                                mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
709                                mcd.cChannels = 1;
710                                mr = mixerSetControlDetails((HMIXEROBJ)dwMixerHandle, 
711                                        &mcd, MIXER_SETCONTROLDETAILSF_VALUE);
712
713                                if (mr != MMSYSERR_NOERROR)
714                                {
715                                        ms_error("winsndcard_set_control: mixerSetControlDetails failed. (0x%x)", mr);
716                                        return -1;
717                                }
718                                return 0;
719                        }
720                        break;
721                default:
722                        ms_warning("winsndcard_set_control: unsupported command.");
723        }
724        return -1;
725}
726
727static int winsndcard_get_control(MSSndCard *card, MSSndCardControlElem e){
728        WinSndCard *d=(WinSndCard*)card->data;
729        return -1;
730}
731
732static void winsndcard_init(MSSndCard *card){
733        WinSndCard *c=(WinSndCard *)ms_new(WinSndCard,1);
734        c->removed=0;
735        card->data=c;
736}
737
738static void winsndcard_uninit(MSSndCard *card){
739        ms_free(card->data);
740}
741
742static void winsndcard_detect(MSSndCardManager *m);
743static  MSSndCard *winsndcard_dup(MSSndCard *obj);
744static void winsndcard_unload(MSSndCardManager *m);
745
746MSSndCardDesc winsnd_card_desc={
747        "MME",
748        winsndcard_detect,
749        winsndcard_init,
750        winsndcard_set_level,
751        winsndcard_get_level,
752        winsndcard_set_source,
753        winsndcard_set_control,
754        winsndcard_get_control,
755        ms_winsnd_read_new,
756        ms_winsnd_write_new,
757        winsndcard_uninit,
758        winsndcard_dup,
759        winsndcard_unload
760};
761
762static  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));
767        return card;
768}
769
770static 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);
774        d->in_devid=in_dev;
775        d->out_devid=out_dev;
776        card->capabilities=cap;
777        return card;
778}
779
780static void add_or_update_card(MSSndCardManager *m, const char *name, int indev, int outdev, unsigned int capability){
781        MSSndCard *card;
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;
790                        if (indev!=-1) 
791                                d->in_devid=indev;
792                        if (outdev!=-1)
793                                d->out_devid=outdev;
794                        d->removed=0;
795                        return;
796                }
797        }
798        /* add this new card:*/
799        ms_snd_card_manager_add_card(m,winsndcard_new(name,indev,outdev,capability));
800}
801
802
803static void _winsndcard_detect(MSSndCardManager *m){
804        MMRESULT mr = NOERROR;
805        unsigned int nOutDevices = waveOutGetNumDevs ();
806        unsigned int nInDevices = waveInGetNumDevs ();
807        unsigned int item;
808
809        if (nOutDevices>nInDevices)
810                nInDevices = nOutDevices;
811
812        for (item = 0; item < nInDevices; item++){
813
814                WAVEINCAPS incaps;
815                WAVEOUTCAPS outcaps;
816                mr = waveInGetDevCaps (item, &incaps, sizeof (WAVEINCAPS));
817                if (mr == MMSYSERR_NOERROR)
818                {
819#if defined(_WIN32_WCE)
820                        char card[256];
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); */
824#else
825                        char szName[256];
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);
828#endif
829                }
830                mr = waveOutGetDevCaps (item, &outcaps, sizeof (WAVEOUTCAPS));
831                if (mr == MMSYSERR_NOERROR)
832                {
833#if defined(_WIN32_WCE)
834                        char card[256];
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); */
838#else
839                        char szName[256];
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);
842#endif
843                }
844        }
845}
846
847static void deactivate_removed_cards(MSSndCardManager *m){
848        MSSndCard *card;
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;
856                }
857        }
858}
859
860static void mark_as_removed(MSSndCardManager *m){
861        MSSndCard *card;
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;
868                        d->removed=1;
869                }
870        }
871}
872
873static ms_thread_t poller_thread=NULL;
874static bool_t poller_running=TRUE;
875
876static void * new_device_polling_thread(void *ignore){
877        MSSndCardManager *m;
878        /*check for new devices every 5 seconds*/
879        while(poller_running){
880                ms_sleep(5);
881                if (poller_running){
882                        m=ms_snd_card_manager_get();
883                        if(!m) break;
884                        mark_as_removed(m);
885                        _winsndcard_detect(m);
886                        deactivate_removed_cards(m);
887                }
888        }
889        return NULL;
890}
891
892static void stop_poller(){
893        poller_running=FALSE;
894        ms_thread_join(poller_thread,NULL);
895        poller_thread=NULL;
896}
897
898static void winsndcard_unload(MSSndCardManager *m){
899        stop_poller();
900}
901
902static 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);
906}
907
908typedef struct WinSnd{
909        int dev_id;
910        HWAVEIN indev;
911        HWAVEOUT outdev;
912        WAVEFORMATEX wfx;
913        WAVEHDR hdrs_read[WINSND_NBUFS];
914        WAVEHDR hdrs_write[WINSND_OUT_NBUFS];
915        queue_t rq;
916        ms_mutex_t mutex;
917        uint64_t bytes_read;
918        unsigned int nbufs_playing;
919        bool_t running;
920
921        int32_t stat_input;
922        int32_t stat_output;
923        int32_t stat_notplayed;
924
925        int32_t stat_minimumbuffer;
926
927        queue_t write_rq;
928#ifndef DISABLE_SPEEX
929        SpeexPreprocessState *pst;
930        int pst_frame_size;
931#endif
932        int ready;
933        int workaround; /* workaround for opticon audio device */
934}WinSnd;
935
936static 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;
939}
940
941
942/*#define _TRUE_TIME*/
943#ifndef _TRUE_TIME
944static 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); */
948        return curtime;
949}
950#endif
951
952
953static void winsnd_init(MSFilter *f){
954        WinSnd *d=(WinSnd *)ms_new0(WinSnd,1);
955        d->wfx.wFormatTag = WAVE_FORMAT_PCM;
956        d->wfx.cbSize = 0;
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;
962        qinit(&d->rq);
963        qinit(&d->write_rq);
964#ifndef DISABLE_SPEEX
965        d->pst=NULL;
966        d->pst_frame_size=0;
967#endif
968        d->ready=0;
969        d->workaround=0;
970        ms_mutex_init(&d->mutex,NULL);
971        f->data=d;
972
973        d->stat_input=0;
974        d->stat_output=0;
975        d->stat_notplayed=0;
976        d->stat_minimumbuffer=WINSND_MINIMUMBUFFER;
977}
978
979static void winsnd_uninit(MSFilter *f){
980        WinSnd *d=(WinSnd*)f->data;
981        flushq(&d->rq,0);
982        flushq(&d->write_rq,0);
983#ifndef DISABLE_SPEEX
984        if (d->pst!=NULL)
985                speex_preprocess_state_destroy(d->pst);
986        d->pst=NULL;
987        d->pst_frame_size=0;
988#endif
989        d->ready=0;
990        d->workaround=0;
991        ms_mutex_destroy(&d->mutex);
992        ms_free(f->data);
993}
994
995static void add_input_buffer(WinSnd *d, WAVEHDR *hdr, int buflen){
996        mblk_t *m=allocb(buflen,0);
997        MMRESULT mr;
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;
1002        hdr->dwFlags = 0;
1003        hdr->dwUser = (DWORD)m;
1004        mr = waveInPrepareHeader (d->indev,hdr,sizeof(*hdr));
1005        if (mr != MMSYSERR_NOERROR){
1006                ms_error("waveInPrepareHeader() error");
1007                return ;
1008        }
1009        mr=waveInAddBuffer(d->indev,hdr,sizeof(*hdr));
1010        if (mr != MMSYSERR_NOERROR){
1011                ms_error("waveInAddBuffer() error");
1012                return ;
1013        }
1014}
1015
1016static void CALLBACK
1017read_callback (HWAVEIN waveindev, UINT uMsg, DWORD dwInstance, DWORD dwParam1,
1018                           DWORD dwParam2)
1019{
1020        WAVEHDR *wHdr=(WAVEHDR *) dwParam1;
1021        MSFilter *f=(MSFilter *)dwInstance;
1022        WinSnd *d=(WinSnd*)f->data;
1023        mblk_t *m;
1024        int bsize;
1025        switch (uMsg){
1026                case WIM_OPEN:
1027                        ms_debug("read_callback : WIM_OPEN");
1028                        break;
1029                case WIM_CLOSE:
1030                        ms_debug("read_callback : WIM_CLOSE");
1031                        break;
1032                case WIM_DATA:
1033                        bsize=wHdr->dwBytesRecorded;
1034                        if (bsize<=0) {
1035#if 0
1036                                if (d->running==TRUE) /* avoid adding buffer back when calling waveInReset */
1037                                {
1038                                        MMRESULT mr;
1039                                        mr=waveInAddBuffer(d->indev,wHdr,sizeof(*wHdr));
1040                                        if (mr != MMSYSERR_NOERROR){
1041                                                ms_error("waveInAddBuffer() error");
1042                                                return ;
1043                                        }
1044                                        ms_warning("read_callback : EMPTY DATA, WIM_DATA (%p,%i)",wHdr,bsize);
1045                                }
1046                                m=(mblk_t*)wHdr->dwUser;
1047                                wHdr->dwUser=0;
1048                                freemsg(m);
1049                                return;
1050#endif
1051                        }
1052
1053                        /* ms_warning("read_callback : WIM_DATA (%p,%i)",wHdr,bsize); */
1054                        m=(mblk_t*)wHdr->dwUser;
1055                        m->b_wptr+=bsize;
1056                        wHdr->dwUser=0;
1057                        ms_mutex_lock(&d->mutex);
1058                        putq(&d->rq,m);
1059                        ms_mutex_unlock(&d->mutex);
1060                        d->bytes_read+=wHdr->dwBufferLength;
1061                        d->stat_input++;
1062                        d->stat_input++;
1063#ifdef WIN32_TIMERS
1064                        if (f->ticker->TimeEvent!=NULL)
1065                                SetEvent(f->ticker->TimeEvent);
1066#endif
1067                        break;
1068        }
1069}
1070
1071
1072static void winsnd_read_preprocess(MSFilter *f){
1073        WinSnd *d=(WinSnd*)f->data;
1074        MMRESULT mr;
1075        int i;
1076        int bsize;
1077        DWORD dwFlag;
1078
1079        d->stat_input=0;
1080        d->stat_output=0;
1081        d->stat_notplayed=0;
1082        d->stat_minimumbuffer=WINSND_MINIMUMBUFFER;
1083
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)
1090        {
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);
1096        }
1097        if (mr != MMSYSERR_NOERROR)
1098        {
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)
1103                {
1104                        d->indev=NULL;
1105                        ms_error("Failed to prepare windows sound device. (waveInOpen:0x%i)", mr);
1106                        return ;
1107                }
1108        }
1109#ifndef _TRUE_TIME
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);
1113#endif
1114
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);
1120        }
1121        d->running=TRUE;
1122        mr=waveInStart(d->indev);
1123        if (mr != MMSYSERR_NOERROR){
1124                ms_error("waveInStart() error");
1125#ifndef _TRUE_TIME
1126                ms_mutex_lock(&f->ticker->lock);
1127                ms_ticker_set_time_func(f->ticker,NULL,NULL);
1128                ms_mutex_unlock(&f->ticker->lock);
1129#endif
1130                return ;
1131        }
1132}
1133
1134static void winsnd_read_postprocess(MSFilter *f){
1135        WinSnd *d=(WinSnd*)f->data;
1136        MMRESULT mr;
1137        int i;
1138#ifndef _TRUE_TIME
1139        ms_mutex_lock(&f->ticker->lock);
1140        ms_ticker_set_time_func(f->ticker,NULL,NULL);
1141        ms_mutex_unlock(&f->ticker->lock);
1142#endif
1143        d->running=FALSE;
1144        mr=waveInStop(d->indev);
1145        if (mr != MMSYSERR_NOERROR){
1146                ms_error("waveInStop() error");
1147                return ;
1148        }
1149        mr=waveInReset(d->indev);
1150        if (mr != MMSYSERR_NOERROR){
1151                ms_error("waveInReset() error");
1152                return ;
1153        }
1154        for(i=0;i<WINSND_NBUFS;++i){
1155                WAVEHDR *hdr=&d->hdrs_read[i];
1156                if (hdr->dwFlags & WHDR_PREPARED)
1157                {
1158                        mr = waveInUnprepareHeader(d->indev,hdr,sizeof (*hdr));
1159                        if (mr != MMSYSERR_NOERROR){
1160                                ms_error("waveInUnPrepareHeader() error");
1161                        }
1162                }
1163        }
1164        mr = waveInClose(d->indev);
1165        if (mr != MMSYSERR_NOERROR){
1166                ms_error("waveInClose() error");
1167                return ;
1168        }
1169
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);
1171        flushq(&d->rq,0);
1172}
1173
1174static void winsnd_read_process(MSFilter *f){
1175        WinSnd *d=(WinSnd*)f->data;
1176        mblk_t *m;
1177        int i;
1178        ms_mutex_lock(&d->mutex);
1179        while((m=getq(&d->rq))!=NULL){
1180                ms_queue_put(f->outputs[0],m);
1181        }
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) {
1186                        MMRESULT mr;
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);
1191                }
1192        }
1193}
1194
1195static void CALLBACK
1196write_callback(HWAVEOUT outdev, UINT uMsg, DWORD dwInstance,
1197                           DWORD dwParam1, DWORD dwParam2)
1198{
1199        WAVEHDR *hdr=(WAVEHDR *) dwParam1;
1200        WinSnd *d=(WinSnd*)dwInstance;
1201
1202        switch (uMsg){
1203                case WOM_OPEN:
1204                        break;
1205                case WOM_CLOSE:
1206                case WOM_DONE:
1207                        if (hdr){
1208                                d->nbufs_playing--;
1209                        }
1210                        if (d->stat_output==0)
1211                        {
1212                                d->stat_input=1; /* reset */
1213                                d->stat_notplayed=0;
1214                        }
1215                        d->stat_output++;
1216                        break;
1217        }
1218}
1219
1220static void winsnd_write_preprocess(MSFilter *f){
1221        WinSnd *d=(WinSnd*)f->data;
1222        MMRESULT mr;
1223        DWORD dwFlag;
1224        int i;
1225
1226        d->stat_input=0;
1227        d->stat_output=0;
1228        d->stat_notplayed=0;
1229        d->stat_minimumbuffer=WINSND_MINIMUMBUFFER;
1230
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)
1237        {
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);
1243        }
1244        if (mr != MMSYSERR_NOERROR)
1245        {
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)
1250                {
1251                        ms_error("Failed to open windows sound device %i. (waveOutOpen:0x%i)",d->dev_id, mr);
1252                        d->outdev=NULL;
1253                        return ;
1254                }
1255        }
1256        for(i=0;i<WINSND_OUT_NBUFS;++i){
1257                WAVEHDR *hdr=&d->hdrs_write[i];
1258                hdr->dwFlags=0;
1259                hdr->dwUser=0;
1260        }
1261}
1262
1263static void winsnd_write_postprocess(MSFilter *f){
1264        WinSnd *d=(WinSnd*)f->data;
1265        MMRESULT mr;
1266        int i;
1267        if (d->outdev==NULL) return;
1268        mr=waveOutReset(d->outdev);
1269        if (mr != MMSYSERR_NOERROR){
1270                ms_error("waveOutReset() error");
1271                return ;
1272        }
1273        for(i=0;i<WINSND_OUT_NBUFS;++i){
1274                WAVEHDR *hdr=&d->hdrs_write[i];
1275                mblk_t *old;
1276                if (hdr->dwFlags & WHDR_DONE){
1277                        mr=waveOutUnprepareHeader(d->outdev,hdr,sizeof(*hdr));
1278                        if (mr != MMSYSERR_NOERROR){
1279                                ms_error("waveOutUnprepareHeader error");
1280                        }
1281                        old=(mblk_t*)hdr->dwUser;
1282                        if (old) freemsg(old);
1283                        hdr->dwUser=0;
1284                }
1285        }
1286        mr=waveOutClose(d->outdev);
1287        if (mr != MMSYSERR_NOERROR){
1288                ms_error("waveOutClose() error");
1289                return ;
1290        }
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);
1293        d->ready=0;
1294        d->workaround=0;
1295
1296#ifndef DISABLE_SPEEX
1297        if (d->pst!=NULL)
1298                speex_preprocess_state_destroy(d->pst);
1299        d->pst=NULL;
1300        d->pst_frame_size=0;
1301#endif
1302}
1303
1304static void winsnd_write_process(MSFilter *f){
1305        WinSnd *d=(WinSnd*)f->data;
1306        mblk_t *m,*old;
1307        MMRESULT mr;
1308        int i;
1309        int discarded=0;
1310        int possible_size=0;
1311
1312        if (d->outdev==NULL) {
1313                ms_queue_flush(f->inputs[0]);
1314                return;
1315        }
1316
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)
1321                {
1322                        d->pst_frame_size=possible_size;
1323
1324                        d->pst = speex_preprocess_state_init(d->pst_frame_size/2, d->wfx.nSamplesPerSec);
1325                        if (d->pst!=NULL) {
1326                                float f;
1327                                i=1;
1328                                speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_VAD, &i);
1329                                i=0;
1330                                speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_DENOISE, &i);
1331                                i=0;
1332                                speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_AGC, &i);
1333                                f=8000;
1334                                speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_AGC_LEVEL, &f);
1335                                i=0;
1336                                speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_DEREVERB, &i);
1337                        }
1338                }
1339#endif
1340
1341                putq(&d->write_rq,m);
1342        }
1343
1344#ifdef AMD_HACK
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;
1349#endif
1350
1351        if (d->wfx.nSamplesPerSec>=32000) /* better results for high rates */
1352        {
1353                if (d->nbufs_playing+d->write_rq.q_mcount<4)
1354                {
1355                        d->ready=0;
1356                }
1357        }
1358        else
1359        {
1360                if (d->nbufs_playing+d->write_rq.q_mcount<7)
1361                {
1362                        d->ready=0;
1363                }
1364        }
1365#if defined(WCE_OPTICON_WORKAROUND)
1366        if (d->workaround==0)
1367        {
1368                d->workaround=1;
1369                Sleep(WCE_OPTICON_WORKAROUND);
1370        }
1371#endif
1372
1373        while((m=peekq(&d->write_rq))!=NULL){
1374
1375#ifndef DISABLE_SPEEX
1376                int vad=1;
1377                if (d->pst!=NULL && msgdsize(m)==d->pst_frame_size && d->pst_frame_size<=4096)
1378                {
1379                        char tmp[4096];
1380                        memcpy(tmp, m->b_rptr, msgdsize(m));
1381                        vad = speex_preprocess(d->pst, (short*)tmp, NULL);
1382
1383                        if (d->ready==0)
1384                        {
1385                                if (vad==0)
1386                                {
1387                                        int missing;
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;
1391
1392                                        ms_message("WINSND trouble: inserting %i silence", missing);
1393                                        while(missing>0)
1394                                        {
1395                                                old=dupb(m);
1396                                                putq(&d->write_rq,old);
1397                                                missing--;
1398                                        }
1399                                }
1400                                d->ready=1;
1401                        }
1402                }
1403#else
1404                if (d->ready==0)
1405                {
1406                        int missing;
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);
1411                        while(missing>0)
1412                        {
1413                                old=dupb(m);
1414                                putq(&d->write_rq,old);
1415                                missing--;
1416                        }
1417                        d->ready=1;
1418                }
1419#endif
1420
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");
1428                                }
1429                                freemsg(old);
1430                                hdr->dwUser=0;
1431                        }
1432                        if (hdr->dwUser==0){
1433                                hdr->lpData=(LPSTR)m->b_rptr;
1434                                hdr->dwBufferLength=msgdsize(m);
1435                                hdr->dwFlags = 0;
1436                                hdr->dwUser = (DWORD)m;
1437                                mr = waveOutPrepareHeader(d->outdev,hdr,sizeof(*hdr));
1438                                if (mr != MMSYSERR_NOERROR){
1439                                        ms_error("waveOutPrepareHeader() error");
1440                                        getq(&d->write_rq);
1441                                        freemsg(m);
1442                                        discarded++;
1443                                        d->stat_notplayed++;
1444                                        break;
1445                                }
1446                                mr=waveOutWrite(d->outdev,hdr,sizeof(*hdr));
1447                                if (mr != MMSYSERR_NOERROR){
1448                                        ms_error("waveOutWrite() error");
1449                                        getq(&d->write_rq);
1450                                        freemsg(m);
1451                                        discarded++;
1452                                        d->stat_notplayed++;
1453                                        break;
1454                                }else {
1455                                        getq(&d->write_rq);
1456                                        d->nbufs_playing++;
1457                                        /* ms_debug("waveOutWrite() done"); */
1458                                }
1459                                break;
1460                        }
1461                }
1462                if (i==d->stat_minimumbuffer){
1463                        /* ms_error("winsnd_write_process: All buffers are busy."); */
1464#ifndef DISABLE_SPEEX
1465                        if (d->pst==NULL)
1466                        {
1467                                /* initial behavior (detection in process?) */
1468                                getq(&d->write_rq);
1469                                freemsg(m);
1470                                discarded++;
1471                                d->stat_notplayed++;
1472                        }
1473                        else
1474                        {
1475                                if (vad==0)
1476                                {
1477                                        getq(&d->write_rq);
1478                                        freemsg(m);
1479                                        ms_message("WINSND trouble: silence removed");
1480                                        discarded++;
1481                                        d->stat_notplayed++;
1482                                }
1483                        }
1484#else
1485                        getq(&d->write_rq);
1486                        freemsg(m);
1487                        discarded++;
1488                        d->stat_notplayed++;
1489#endif
1490
1491                        break;
1492                }
1493        }
1494}
1495
1496static int get_rate(MSFilter *f, void *arg){
1497        WinSnd *d=(WinSnd*)f->data;
1498        *((int*)arg)=d->wfx.nSamplesPerSec;
1499        return 0;
1500}
1501
1502static int set_rate(MSFilter *f, void *arg){
1503        WinSnd *d=(WinSnd*)f->data;
1504        d->wfx.nSamplesPerSec=*((int*)arg);
1505        d->wfx.nSamplesPerSec=44100;
1506        return 0;
1507}
1508
1509static int set_nchannels(MSFilter *f, void *arg){
1510        WinSnd *d=(WinSnd*)f->data;
1511        d->wfx.nChannels=*((int*)arg);
1512        return 0;
1513}
1514
1515static int winsnd_get_stat_input(MSFilter *f, void *arg){
1516        WinSnd *d=(WinSnd*)f->data;
1517        return d->stat_input;
1518}
1519
1520static int winsnd_get_stat_ouptut(MSFilter *f, void *arg){
1521        WinSnd *d=(WinSnd*)f->data;
1522
1523        return d->stat_output;
1524}
1525
1526static int winsnd_get_stat_discarded(MSFilter *f, void *arg){
1527        WinSnd *d=(WinSnd*)f->data;
1528
1529        return d->stat_notplayed;
1530}
1531
1532static 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 },
1539        {       0                               , NULL          }
1540};
1541
1542MSFilterDesc winsnd_read_desc={
1543        MS_WINSND_READ_ID,
1544        "MMERead",
1545        "MME capture filter for Windows",
1546        MS_FILTER_OTHER,
1547        NULL,
1548        0,
1549        1,
1550        winsnd_init,
1551        winsnd_read_preprocess,
1552        winsnd_read_process,
1553        winsnd_read_postprocess,
1554        winsnd_uninit,
1555        winsnd_methods
1556};
1557
1558
1559MSFilterDesc winsnd_write_desc={
1560        MS_WINSND_WRITE_ID,
1561        "MMEWrite",
1562        "MME playback filter for Windows",
1563        MS_FILTER_OTHER,
1564        NULL,
1565        1,
1566        0,
1567        winsnd_init,
1568        winsnd_write_preprocess,
1569        winsnd_write_process,
1570        winsnd_write_postprocess,
1571        winsnd_uninit,
1572        winsnd_methods
1573};
1574
1575MSFilter *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;
1580        return f;
1581}
1582
1583
1584MSFilter *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;
1589        return f;
1590}
1591
1592MS_FILTER_DESC_EXPORT(winsnd_read_desc)
1593MS_FILTER_DESC_EXPORT(winsnd_write_desc)
Note: See TracBrowser for help on using the repository browser.