source: mediastreamer2/linphone/mediastreamer2/src/winsndds.cpp @ 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

File size: 56.1 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#ifdef __DIRECTSOUND_ENABLED__
21
22#include "mediastreamer2/mssndcard.h"
23#include "mediastreamer2/msfilter.h"
24#include "mediastreamer2/msticker.h"
25
26#define UNICODE
27
28#include <mmsystem.h>
29#ifdef _MSC_VER
30#include <mmreg.h>
31#endif
32#include <msacm.h>
33
34#include <dsound.h>
35#include <dsconf.h>
36
37const GUID GUID_DSCFX_MS_AEC = {0xcdebb919, 0x379a, 0x488a, {0x87, 0x65, 0xf5, 0x3c, 0xfd, 0x36, 0xde, 0x40}};
38const GUID GUID_DSCFX_CLASS_AEC = {0xBF963D80L, 0xC559, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}}; 
39
40const GUID CLSID_DirectSoundPrivate= { 0x11ab3ec0, 0x25ec, 0x11d1, {0xa4, 0xd8, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca}};
41const GUID DSPROPSETID_DirectSoundDevice = {0x84624f82, 0x25ec, 0x11d1, {0xa4, 0xd8, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca}};
42
43#define WINSNDDS_MINIMUMBUFFER 5
44
45static MSFilter *ms_winsndds_read_new(MSSndCard *card);
46static MSFilter *ms_winsndds_write_new(MSSndCard *card);
47
48static HMODULE ms_lib_instance=NULL;
49static HRESULT (WINAPI *ms_DllGetClassObject)(REFCLSID , REFIID , LPVOID *);
50
51static HRESULT (WINAPI *ms_DirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
52static HRESULT (WINAPI *ms_DirectSoundEnumerate)(LPDSENUMCALLBACKW, LPVOID);
53
54static HRESULT (WINAPI *ms_DirectSoundCaptureCreate)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN);
55static HRESULT (WINAPI *ms_DirectSoundCaptureEnumerate)(LPDSENUMCALLBACKW, LPVOID);
56
57static HRESULT (WINAPI *ms_DirectSoundFullDuplexCreate)(LPCGUID , LPCGUID ,
58                                                                                                                LPCDSCBUFFERDESC , LPCDSBUFFERDESC , HWND ,
59                                                                                                                DWORD , LPDIRECTSOUNDFULLDUPLEX* , LPDIRECTSOUNDCAPTUREBUFFER8 *,
60                                                                                                                LPDIRECTSOUNDBUFFER8 *, LPUNKNOWN );
61
62typedef struct WinSndDsCard{
63        int in_devid;
64        int out_devid;
65        GUID in_guid;
66        GUID out_guid;
67        int removed;
68}WinSndDsCard;
69
70static BOOL GetWaveIdFromDSoundGUID( GUID i_sGUID, DWORD *dwWaveID)
71{ 
72    LPKSPROPERTYSET         pKsPropertySet = NULL; 
73    LPCLASSFACTORY          pClassFactory  = NULL; 
74    HRESULT                 hr;
75        BOOL                                    retval = FALSE;
76
77        PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA psDirectSoundDeviceDescription = NULL; 
78        DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA sDirectSoundDeviceDescription;
79
80        memset(&sDirectSoundDeviceDescription,0,sizeof(sDirectSoundDeviceDescription)); 
81
82    hr = ms_DllGetClassObject (CLSID_DirectSoundPrivate, IID_IClassFactory, (LPVOID *)&pClassFactory );
83
84    if(SUCCEEDED(hr)) 
85    { 
86        hr = pClassFactory->CreateInstance ( NULL, IID_IKsPropertySet, (LPVOID *)&pKsPropertySet ); 
87    } 
88
89    // Release the class factory
90    if(pClassFactory) 
91    { 
92        pClassFactory->Release(); 
93    }
94
95    if(SUCCEEDED(hr)) 
96        { 
97                ULONG ulBytesReturned = 0;
98                sDirectSoundDeviceDescription.DeviceId = i_sGUID; 
99
100                // On the first call the final size is unknown so pass the size of the struct in order to receive
101                // "Type" and "DataFlow" values, ulBytesReturned will be populated with bytes required for struct+strings.
102        hr = pKsPropertySet->Get(DSPROPSETID_DirectSoundDevice, 
103                DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION, 
104                NULL, 
105                0, 
106                &sDirectSoundDeviceDescription, 
107                sizeof(sDirectSoundDeviceDescription), 
108                &ulBytesReturned
109            ); 
110
111                if (ulBytesReturned)
112                {
113                        // On the first call it notifies us of the required amount of memory in order to receive the strings.
114                        // Allocate the required memory, the strings will be pointed to the memory space directly after the struct.
115                        psDirectSoundDeviceDescription = (PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA)new BYTE[ulBytesReturned];
116                        *psDirectSoundDeviceDescription = sDirectSoundDeviceDescription;
117
118                        hr = pKsPropertySet->Get(DSPROPSETID_DirectSoundDevice, 
119                                        DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION, 
120                                        NULL, 
121                                        0, 
122                                        psDirectSoundDeviceDescription, 
123                                        ulBytesReturned, 
124                                        &ulBytesReturned
125                                ); 
126
127                        *dwWaveID  = psDirectSoundDeviceDescription->WaveDeviceId;
128                        delete [] psDirectSoundDeviceDescription;
129                        retval = TRUE;
130                }
131
132                pKsPropertySet->Release(); 
133        } 
134
135        return retval; 
136} 
137
138static void winsnddscard_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent){
139        WinSndDsCard *d=(WinSndDsCard*)card->data;
140        DWORD waveout_devid = WAVE_MAPPER;
141        DWORD wavein_devid = WAVE_MAPPER;
142
143        UINT uMixerID;
144        DWORD dwMixerHandle;
145        MIXERLINE MixerLine;
146        MIXERLINE Line;
147        UINT uLineIndex;
148
149        MIXERLINECONTROLS mlc = {0};
150        MIXERCONTROL mc = {0};
151        MIXERCONTROLDETAILS mcd = {0};
152        MIXERCONTROLDETAILS_UNSIGNED mcdu = {0};
153
154        MMRESULT mr = MMSYSERR_NOERROR;
155        DWORD dwVolume = ((0xFFFF) * percent) / 100;
156       
157        WORD wLeftVol, wRightVol;
158        DWORD dwNewVol;
159        wLeftVol = LOWORD(dwVolume); // get higher WORD
160        wRightVol = LOWORD(dwVolume); // get lower WORD
161
162        dwNewVol = MAKELONG(wLeftVol, wRightVol);
163
164        GetWaveIdFromDSoundGUID(d->in_guid, &wavein_devid);
165        GetWaveIdFromDSoundGUID(d->out_guid, &waveout_devid);
166
167        switch(e){
168                case MS_SND_CARD_PLAYBACK:
169                case MS_SND_CARD_MASTER:
170                        {
171
172                                mr = mixerGetID( (HMIXEROBJ)waveout_devid, &uMixerID, MIXER_OBJECTF_WAVEOUT );
173                                if ( mr != MMSYSERR_NOERROR )
174                                {
175                                        ms_error("winsndcard_set_level: mixerGetID failed. (0x%x)", mr);
176                                        return;
177                                }
178                                mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
179                                if ( mr != MMSYSERR_NOERROR )
180                                {
181                                        mixerClose( (HMIXER)dwMixerHandle );
182                                        ms_error("winsndcard_set_level: mixerOpen failed. (0x%x)", mr);
183                                        return;
184                                }
185                                memset( &MixerLine, 0, sizeof(MIXERLINE) );
186                                MixerLine.cbStruct = sizeof(MIXERLINE);
187                                if (MS_SND_CARD_MASTER==e)
188                                        MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
189                                else
190                                        MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
191                                mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE );
192                                if ( mr != MMSYSERR_NOERROR )
193                                {
194                                        mixerClose( (HMIXER)dwMixerHandle );
195                                        ms_error("winsndcard_set_level: mixerGetLineInfo failed. (0x%x)", mr);
196                                        return;
197                                }
198
199                                /* ms_message("Name: %s\n", MixerLine.szName); */
200                                /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
201                                /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
202
203                                mlc.cbStruct = sizeof(MIXERLINECONTROLS);
204                                mlc.dwLineID = MixerLine.dwLineID;
205                                mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
206                                mlc.cControls = 1;
207                                mlc.pamxctrl = &mc;
208                                mlc.cbmxctrl = sizeof(MIXERCONTROL);
209                                mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle, 
210                                        &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
211
212                                if (mr != MMSYSERR_NOERROR)
213                                {
214                                        ms_error("winsndcard_set_level: mixerGetLineControls failed. (0x%x)", mr);
215                                        return;
216                                }
217
218                                mcdu.dwValue = 65535*percent/100; /* the volume is a number between 0 and 65535 */
219
220                                mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
221                                mcd.hwndOwner = 0;
222                                mcd.dwControlID = mc.dwControlID;
223                                mcd.paDetails = &mcdu;
224                                mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
225                                mcd.cChannels = 1;
226                                mr = mixerSetControlDetails((HMIXEROBJ)dwMixerHandle, 
227                                        &mcd, MIXER_SETCONTROLDETAILSF_VALUE);
228
229                                if (mr != MMSYSERR_NOERROR)
230                                {
231                                        ms_error("winsndcard_set_level: mixerSetControlDetails failed. (0x%x)", mr);
232                                        return;
233                                }
234                        }
235                        break;
236                case MS_SND_CARD_CAPTURE:
237                        mr = mixerGetID( (HMIXEROBJ)wavein_devid, &uMixerID, MIXER_OBJECTF_WAVEIN );
238                        if ( mr != MMSYSERR_NOERROR )
239                        {
240                                ms_error("winsndcard_set_level: mixerGetID failed. (0x%x)", mr);
241                                return;
242                        }
243                        mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );                       
244                        if ( mr != MMSYSERR_NOERROR )
245                        {
246                                mixerClose( (HMIXER)dwMixerHandle );
247                                ms_error("winsndcard_set_level: mixerGetLineInfo failed. (0x%x)", mr);
248                                return;
249                        }
250                        memset( &MixerLine, 0, sizeof(MIXERLINE) );
251                        MixerLine.cbStruct = sizeof(MIXERLINE);
252                        MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
253                        mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE );
254                        if ( mr != MMSYSERR_NOERROR )
255                        {
256                                mixerClose( (HMIXER)dwMixerHandle );
257                                ms_error("winsndcard_set_level: mixerGetLineInfo failed. (0x%x)", mr);
258                                return;
259                        }
260
261                        /* ms_message("Name: %s\n", MixerLine.szName); */
262                        /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
263                        /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
264
265                        mlc.cbStruct = sizeof(MIXERLINECONTROLS);
266                        mlc.dwLineID = MixerLine.dwLineID;
267                        mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
268                        mlc.cControls = 1;
269                        mlc.pamxctrl = &mc;
270                        mlc.cbmxctrl = sizeof(MIXERCONTROL);
271                        mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle, 
272                                &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
273
274                        if (mr == MMSYSERR_NOERROR)
275                        {
276                                mcdu.dwValue = 65535*percent/100; /* the volume is a number between 0 and 65535 */
277
278                                mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
279                                mcd.hwndOwner = 0;
280                                mcd.dwControlID = mc.dwControlID;
281                                mcd.paDetails = &mcdu;
282                                mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
283                                mcd.cChannels = 1;
284                                mr = mixerSetControlDetails((HMIXEROBJ)dwMixerHandle, 
285                                        &mcd, MIXER_SETCONTROLDETAILSF_VALUE);
286
287                                if (mr == MMSYSERR_NOERROR)
288                                {
289                                        return;
290                                }
291                                ms_error("winsndcard_set_level: mixerSetControlDetails failed. (0x%x)", mr);
292                                ms_warning("winsndcard_set_level: control the SRC_MICROPHONE instead");
293                        }
294                        else
295                        {
296                                ms_error("winsndcard_set_level: mixerGetLineControls failed. (0x%x)", mr);
297                                ms_warning("winsndcard_set_level: control the SRC_MICROPHONE instead");
298                        }
299
300                        /* In case capture doesn't work: use the SRC_MICROPHONE volume */
301
302                        for (uLineIndex = 0; uLineIndex < MixerLine.cConnections; uLineIndex++)
303                        {
304                                memset( &Line, 0, sizeof(MIXERLINE) );
305                                Line.cbStruct = sizeof(MIXERLINE);
306                                Line.dwDestination = MixerLine.dwDestination;
307                                Line.dwSource = uLineIndex;
308                                mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &Line, MIXER_GETLINEINFOF_LINEID);
309                                if ( mr != MMSYSERR_NOERROR )
310                                {
311                                        mixerClose( (HMIXER)dwMixerHandle );
312                                        ms_error("winsndcard_set_level: mixerGetLineInfo failed. (0x%x)", mr);
313                                        return;
314                                }
315
316                                /* ms_message("Name: %s\n", MixerLine.szName); */
317                                /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
318                                /* ms_message("LineID: %d\n", MixerLine.dwLineID); */
319                                /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
320
321                                memset( &Line, 0, sizeof(MIXERLINE) );
322                                Line.cbStruct = sizeof(MIXERLINE);
323                                Line.dwDestination = MixerLine.dwDestination;
324                                Line.dwSource = uLineIndex;
325                                mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &Line, MIXER_GETLINEINFOF_SOURCE);
326                                if ( mr != MMSYSERR_NOERROR )
327                                {
328                                        mixerClose( (HMIXER)dwMixerHandle );
329                                        ms_error("winsndcard_set_level: mixerGetLineInfo failed. (0x%x)", mr);
330                                        return;
331                                }
332
333                                /* ms_message("Name: %s\n", MixerLine.szName); */
334                                /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
335                                /* ms_message("LineID: %d\n", MixerLine.dwLineID); */
336                                /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
337
338                                if (MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE == Line.dwComponentType) 
339                                {
340                                        LPMIXERCONTROL pmxctrl = (LPMIXERCONTROL)malloc(sizeof(MIXERCONTROL));
341                                        MIXERLINECONTROLS mxlctrl = {sizeof(mxlctrl), Line.dwLineID, MIXERCONTROL_CONTROLTYPE_VOLUME, 1, sizeof(MIXERCONTROL), pmxctrl};
342                                        mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle, &mxlctrl, MIXER_GETLINECONTROLSF_ONEBYTYPE);
343                                        if(!mr){
344                                                DWORD cChannels = Line.cChannels;
345                                                LPMIXERCONTROLDETAILS_UNSIGNED pUnsigned;
346                                                MIXERCONTROLDETAILS mxcd;
347                                                if (MIXERCONTROL_CONTROLF_UNIFORM & pmxctrl->fdwControl) 
348                                                        cChannels = 1; 
349                                                pUnsigned = 
350                                                        (LPMIXERCONTROLDETAILS_UNSIGNED) 
351                                                        malloc(cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
352
353                                                mxcd.cbStruct = sizeof(mxcd);
354                                                mxcd.dwControlID = pmxctrl->dwControlID;
355                                                mxcd.cChannels = cChannels;
356                                                mxcd.hwndOwner = (HWND)0;
357                                                mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
358                                                mxcd.paDetails = (LPVOID) pUnsigned;
359
360                                                mr = mixerGetControlDetails((HMIXEROBJ)dwMixerHandle, &mxcd, 
361                                                        MIXER_SETCONTROLDETAILSF_VALUE); 
362                                                if(!mr){
363                                                        pUnsigned[0].dwValue = pUnsigned[cChannels - 1].dwValue
364                                                                =  pmxctrl->Bounds.dwMaximum*percent/100;
365                                                        mr = mixerSetControlDetails((HMIXEROBJ)dwMixerHandle, &mxcd, 
366                                                                MIXER_SETCONTROLDETAILSF_VALUE); 
367                                                        if(mr){
368                                                                ms_error("winsndcard_set_level: mixerSetControlDetails failed. (0x%x)", mr);
369                                                        }
370                                                }
371                                                else 
372                                                {
373                                                        ms_error("winsndcard_set_level: mixerGetControlDetails failed. (0x%x)", mr);
374                                                }
375                                                free(pmxctrl); 
376                                                free(pUnsigned);
377                                        } 
378                                        else 
379                                        {
380                                                ms_error("winsndcard_set_level: mixerGetLineControls failed. (0x%x)", mr);
381                                                free(pmxctrl);
382                                        }
383                                }
384                        }
385                        mixerClose( (HMIXER)dwMixerHandle );
386                        if (mr != MMSYSERR_NOERROR)
387                        {
388                                ms_error("winsndcard_set_level: mixerClose failed. (0x%x)", mr);
389                                return;
390                        }
391                        break;
392                default:
393                        ms_warning("winsnd_card_set_level: unsupported command.");
394        }
395}
396
397static int winsnddscard_get_level(MSSndCard *card, MSSndCardMixerElem e){
398        WinSndDsCard *d=(WinSndDsCard*)card->data;
399        DWORD waveout_devid = WAVE_MAPPER;
400        DWORD wavein_devid = WAVE_MAPPER;
401
402        UINT uMixerID;
403        DWORD dwMixerHandle;
404        MIXERLINE MixerLine;
405        MIXERLINE Line;
406        UINT uLineIndex;
407
408        MIXERLINECONTROLS mlc = {0};
409        MIXERCONTROL mc = {0};
410        MIXERCONTROLDETAILS mcd = {0};
411        MIXERCONTROLDETAILS_UNSIGNED mcdu = {0};
412
413        MMRESULT mr = MMSYSERR_NOERROR;
414        int percent;
415
416        GetWaveIdFromDSoundGUID(d->in_guid, &wavein_devid);
417        GetWaveIdFromDSoundGUID(d->out_guid, &waveout_devid);
418
419        switch(e){
420                case MS_SND_CARD_MASTER:
421                case MS_SND_CARD_PLAYBACK:
422                        {
423                                mr = mixerGetID( (HMIXEROBJ)waveout_devid, &uMixerID, MIXER_OBJECTF_WAVEOUT );
424                                if ( mr != MMSYSERR_NOERROR )
425                                {
426                                        ms_error("winsndcard_get_level: mixerGetID failed. (0x%x)", mr);
427                                        return -1;
428                                }
429                                mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
430                                if ( mr != MMSYSERR_NOERROR )
431                                {
432                                        mixerClose( (HMIXER)dwMixerHandle );
433                                        ms_error("winsndcard_get_level: mixerOpen failed. (0x%x)", mr);
434                                        return -1;
435                                }
436                                memset( &MixerLine, 0, sizeof(MIXERLINE) );
437                                MixerLine.cbStruct = sizeof(MIXERLINE);
438                                if (MS_SND_CARD_MASTER==e)
439                                        MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
440                                else
441                                        MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
442                                mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE );
443                                if ( mr != MMSYSERR_NOERROR )
444                                {
445                                        mixerClose( (HMIXER)dwMixerHandle );
446                                        ms_error("winsndcard_get_level: mixerGetLineInfo failed. (0x%x)", mr);
447                                        return -1;
448                                }
449
450                                /* ms_message("Name: %s\n", MixerLine.szName); */
451                                /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
452                                /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
453
454                                mlc.cbStruct = sizeof(MIXERLINECONTROLS);
455                                mlc.dwLineID = MixerLine.dwLineID;
456                                mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
457                                mlc.cControls = 1;
458                                mlc.pamxctrl = &mc;
459                                mlc.cbmxctrl = sizeof(MIXERCONTROL);
460                                mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle, 
461                                        &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
462                                if (mr != MMSYSERR_NOERROR)
463                                {
464                                        ms_error("winsndcard_get_level: mixerGetLineControls failed. (0x%x)", mr);
465                                        return -1;
466                                }
467
468                                mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
469                                mcd.hwndOwner = 0;
470                                mcd.dwControlID = mc.dwControlID;
471                                mcd.paDetails = &mcdu;
472                                mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
473                                mcd.cChannels = 1;
474                                mr = mixerGetControlDetails((HMIXEROBJ)dwMixerHandle, &mcd, 
475                                        MIXER_SETCONTROLDETAILSF_VALUE); 
476                                percent = (mcdu.dwValue *100) / (mc.Bounds.dwMaximum);
477
478                                if (mr != MMSYSERR_NOERROR)
479                                {
480                                        ms_error("winsndcard_get_level: mixerGetControlDetails failed. (0x%x)", mr);
481                                        return -1;
482                                }
483                                return percent;
484                        }
485                        break;
486                case MS_SND_CARD_CAPTURE:
487                        mr = mixerGetID( (HMIXEROBJ)wavein_devid, &uMixerID, MIXER_OBJECTF_WAVEIN );
488                        if ( mr != MMSYSERR_NOERROR )
489                        {
490                                ms_error("winsndcard_get_level: mixerGetID failed. (0x%x)", mr);
491                                return -1;
492                        }
493                        mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
494                        if ( mr != MMSYSERR_NOERROR )
495                        {
496                                mixerClose( (HMIXER)dwMixerHandle );
497                                ms_error("winsndcard_get_level: mixerOpen failed. (0x%x)", mr);
498                                return -1;
499                        }
500                        memset( &MixerLine, 0, sizeof(MIXERLINE) );
501                        MixerLine.cbStruct = sizeof(MIXERLINE);
502                        MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
503                        mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE );
504                        if ( mr != MMSYSERR_NOERROR )
505                        {
506                                mixerClose( (HMIXER)dwMixerHandle );
507                                ms_error("winsndcard_get_level: mixerGetLineInfo failed. (0x%x)", mr);
508                                return -1;
509                        }
510
511                        /* ms_message("Name: %s\n", MixerLine.szName); */
512                        /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
513                        /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
514
515                        mlc.cbStruct = sizeof(MIXERLINECONTROLS);
516                        mlc.dwLineID = MixerLine.dwLineID;
517                        mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
518                        mlc.cControls = 1;
519                        mlc.pamxctrl = &mc;
520                        mlc.cbmxctrl = sizeof(MIXERCONTROL);
521                        mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle, 
522                                &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
523                        if (mr == MMSYSERR_NOERROR)
524                        {
525                                mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
526                                mcd.hwndOwner = 0;
527                                mcd.dwControlID = mc.dwControlID;
528                                mcd.paDetails = &mcdu;
529                                mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
530                                mcd.cChannels = 1;
531                                mr = mixerGetControlDetails((HMIXEROBJ)dwMixerHandle, &mcd, 
532                                        MIXER_SETCONTROLDETAILSF_VALUE); 
533                                percent = (mcdu.dwValue *100) / (mc.Bounds.dwMaximum);
534
535                                if (mr == MMSYSERR_NOERROR)
536                                {
537                                        return percent;
538                                }
539                                ms_error("winsndcard_get_level: mixerGetControlDetails failed. (0x%x)", mr);
540                                ms_warning("winsndcard_get_level: control the SRC_MICROPHONE instead");
541                        }
542                        else
543                        {
544                                ms_error("winsndcard_get_level: mixerGetLineControls failed. (0x%x)", mr);
545                                ms_warning("winsndcard_get_level: control the SRC_MICROPHONE instead");
546                        }
547
548                        for (uLineIndex = 0; uLineIndex < MixerLine.cConnections; uLineIndex++)
549                        {
550                                memset( &Line, 0, sizeof(MIXERLINE) );
551                                Line.cbStruct = sizeof(MIXERLINE);
552                                Line.dwDestination = MixerLine.dwDestination;
553                                Line.dwSource = uLineIndex;
554                                mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &Line, MIXER_GETLINEINFOF_LINEID);
555                                if ( mr != MMSYSERR_NOERROR )
556                                {
557                                        mixerClose( (HMIXER)dwMixerHandle );
558                                        ms_error("winsndcard_get_level: mixerGetLineInfo failed. (0x%x)", mr);
559                                        return -1;
560                                }
561
562                                /* ms_message("Name: %s\n", MixerLine.szName); */
563                                /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
564                                /* ms_message("LineID: %d\n", MixerLine.dwLineID); */
565                                /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
566
567                                memset( &Line, 0, sizeof(MIXERLINE) );
568                                Line.cbStruct = sizeof(MIXERLINE);
569                                Line.dwDestination = MixerLine.dwDestination;
570                                Line.dwSource = uLineIndex;
571                                mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &Line, MIXER_GETLINEINFOF_SOURCE);
572                                if ( mr != MMSYSERR_NOERROR )
573                                {
574                                        mixerClose( (HMIXER)dwMixerHandle );
575                                        ms_error("winsndcard_get_level: mixerGetLineInfo failed. (0x%x)", mr);
576                                        return -1;
577                                }
578
579                                /* ms_message("Name: %s\n", MixerLine.szName); */
580                                /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
581                                /* ms_message("LineID: %d\n", MixerLine.dwLineID); */
582                                /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
583
584                                if (MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE == Line.dwComponentType)
585                                {
586                                        LPMIXERCONTROL pmxctrl = (LPMIXERCONTROL)malloc(sizeof(MIXERCONTROL));
587                                        MIXERLINECONTROLS mxlctrl = {sizeof(mxlctrl), Line.dwLineID, MIXERCONTROL_CONTROLTYPE_VOLUME, 1, sizeof(MIXERCONTROL), pmxctrl}; 
588                                        if(!mixerGetLineControls((HMIXEROBJ)dwMixerHandle, &mxlctrl, 
589                                                MIXER_GETLINECONTROLSF_ONEBYTYPE)){ 
590                                                        DWORD cChannels = Line.cChannels;
591                                                        LPMIXERCONTROLDETAILS_UNSIGNED pUnsigned;
592                                                        MIXERCONTROLDETAILS mxcd;
593                                                        if (MIXERCONTROL_CONTROLF_UNIFORM & pmxctrl->fdwControl) 
594                                                                cChannels = 1; 
595                                                        pUnsigned = 
596                                                                (LPMIXERCONTROLDETAILS_UNSIGNED) 
597                                                                malloc(cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
598
599                                                        mxcd.cbStruct = sizeof(mxcd);
600                                                        mxcd.dwControlID = pmxctrl->dwControlID;
601                                                        mxcd.cChannels = cChannels;
602                                                        mxcd.hwndOwner = (HWND)0;
603                                                        mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
604                                                        mxcd.paDetails = (LPVOID) pUnsigned;
605
606                                                        mixerGetControlDetails((HMIXEROBJ)dwMixerHandle, &mxcd, 
607                                                                MIXER_SETCONTROLDETAILSF_VALUE); 
608                                                        percent = (pUnsigned[0].dwValue *100) / (pmxctrl->Bounds.dwMaximum);
609                                                        free(pmxctrl);
610                                                        free(pUnsigned);
611                                        } 
612                                        else 
613                                                free(pmxctrl); 
614                                }
615                        }
616                        mixerClose( (HMIXER)dwMixerHandle );
617                        if (mr != MMSYSERR_NOERROR)
618                        {
619                                ms_error("winsndcard_get_level: mixerClose failed. (0x%x)", mr);
620                                return -1;
621                        }
622                        return percent;
623                        break;
624                default:
625                        ms_warning("winsndcard_get_level: unsupported command.");
626                        return -1;
627        }
628        return -1;
629}
630
631static void winsnddscard_set_source(MSSndCard *card, MSSndCardCapture source){
632
633        switch(source){
634                case MS_SND_CARD_MIC:
635                        break;
636                case MS_SND_CARD_LINE:
637                        break;
638        }       
639}
640
641static int winsnddscard_set_control(MSSndCard *card, MSSndCardControlElem e, int val){
642        WinSndDsCard *d=(WinSndDsCard*)card->data;
643        DWORD waveout_devid = WAVE_MAPPER;
644        DWORD wavein_devid = WAVE_MAPPER;
645
646        UINT uMixerID;
647        DWORD dwMixerHandle;
648        MIXERLINE MixerLine;
649        MIXERLINE Line;
650        UINT uLineIndex;
651
652        MIXERLINECONTROLS mlc = {0};
653        MIXERCONTROL mc = {0};
654        MIXERCONTROLDETAILS mcd = {0};
655        MIXERCONTROLDETAILS_BOOLEAN bMute;
656
657        MMRESULT mr = MMSYSERR_NOERROR;
658
659        GetWaveIdFromDSoundGUID(d->in_guid, &wavein_devid);
660        GetWaveIdFromDSoundGUID(d->out_guid, &waveout_devid);
661
662        switch(e){
663                case MS_SND_CARD_CAPTURE_MUTE:
664                        bMute.fValue = (val>0);
665
666                        mr = mixerGetID( (HMIXEROBJ)wavein_devid, &uMixerID, MIXER_OBJECTF_WAVEIN );
667                        if ( mr != MMSYSERR_NOERROR )
668                        {
669                                ms_error("winsndcard_set_control: mixerGetID failed. (0x%x)", mr);
670                                return -1;
671                        }
672                        mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
673                        if ( mr != MMSYSERR_NOERROR )
674                        {
675                                mixerClose( (HMIXER)dwMixerHandle );
676                                ms_error("winsndcard_set_control: mixerOpen failed. (0x%x)", mr);
677                                return -1;
678                        }
679                        memset( &MixerLine, 0, sizeof(MIXERLINE) );
680                        MixerLine.cbStruct = sizeof(MIXERLINE);
681                        MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
682                        mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE );
683                        if ( mr != MMSYSERR_NOERROR )
684                        {
685                                mixerClose( (HMIXER)dwMixerHandle );
686                                ms_error("winsndcard_set_control: mixerGetLineInfo failed. (0x%x)", mr);
687                                return -1;
688                        }
689                        /* ms_message("Name: %s\n", MixerLine.szName); */
690                        /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
691                        /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
692
693                        mlc.cbStruct = sizeof(MIXERLINECONTROLS);
694                        mlc.dwLineID = MixerLine.dwLineID;
695                        mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE; //MIXERCONTROL_CONTROLTYPE_VOLUME;
696                        mlc.cControls = 1;
697                        mlc.pamxctrl = &mc;
698                        mlc.cbmxctrl = sizeof(MIXERCONTROL);
699                        mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle, 
700                                &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
701                        if (mr == MMSYSERR_NOERROR)
702                        {
703                                mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
704                                mcd.hwndOwner = 0;
705                                mcd.dwControlID = mc.dwControlID;
706                                mcd.paDetails = &bMute;
707                                mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
708                                mcd.cChannels = 1;
709                                mr = mixerSetControlDetails((HMIXEROBJ)dwMixerHandle, 
710                                        &mcd, MIXER_SETCONTROLDETAILSF_VALUE);
711
712                                if (mr == MMSYSERR_NOERROR)
713                                {
714                                        return 0;
715                                }
716                                ms_error("winsndcard_set_control: mixerSetControlDetails failed. (0x%x)", mr);
717                                ms_warning("winsndcard_get_level: control the SRC_MICROPHONE instead");
718                        }
719                        else
720                        {
721                                ms_error("winsndcard_set_control: mixerGetLineControls failed. (0x%x)", mr);
722                                ms_warning("winsndcard_get_level: control the SRC_MICROPHONE instead");
723                        }
724
725
726                        for (uLineIndex = 0; uLineIndex < MixerLine.cConnections; uLineIndex++)
727                        {
728                                memset( &Line, 0, sizeof(MIXERLINE) );
729                                Line.cbStruct = sizeof(MIXERLINE);
730                                Line.dwDestination = MixerLine.dwDestination;
731                                Line.dwSource = uLineIndex;
732                                mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &Line, MIXER_GETLINEINFOF_LINEID);
733                                if ( mr != MMSYSERR_NOERROR )
734                                {
735                                        mixerClose( (HMIXER)dwMixerHandle );
736                                        ms_error("winsndcard_set_control: mixerGetLineInfo failed. (0x%x)", mr);
737                                        return -1;
738                                }
739                               
740                                /* ms_message("Name: %s\n", MixerLine.szName); */
741                                /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
742                                /* ms_message("LineID: %d\n", MixerLine.dwLineID); */
743                                /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
744
745                                memset( &Line, 0, sizeof(MIXERLINE) );
746                                Line.cbStruct = sizeof(MIXERLINE);
747                                Line.dwDestination = MixerLine.dwDestination;
748                                Line.dwSource = uLineIndex;
749                                mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &Line, MIXER_GETLINEINFOF_SOURCE);
750                                if ( mr != MMSYSERR_NOERROR )
751                                {
752                                        mixerClose( (HMIXER)dwMixerHandle );
753                                        ms_error("winsndcard_set_control: mixerGetLineInfo failed. (0x%x)", mr);
754                                        return -1;
755                                }
756
757                                /* ms_message("Name: %s\n", MixerLine.szName); */
758                                /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
759                                /* ms_message("LineID: %d\n", MixerLine.dwLineID); */
760                                /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
761
762                                if (MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE == Line.dwComponentType)
763                                {
764                                        /* unmute */
765                                        /* Find a mute control, if any, of the microphone line  */
766
767                                        LPMIXERCONTROL pmxctrl = (LPMIXERCONTROL)malloc(sizeof(MIXERCONTROL));
768                                        MIXERLINECONTROLS mxlctrl = {sizeof(mxlctrl), Line.dwLineID, MIXERCONTROL_CONTROLTYPE_MUTE, 1, sizeof(MIXERCONTROL), pmxctrl}; 
769                                        if(!mixerGetLineControls((HMIXEROBJ)dwMixerHandle, &mxlctrl, MIXER_GETLINECONTROLSF_ONEBYTYPE)){ 
770                                                DWORD cChannels = Line.cChannels;
771                                                LPMIXERCONTROLDETAILS_BOOLEAN pbool;
772                                                MIXERCONTROLDETAILS mxcd;
773
774                                                if (MIXERCONTROL_CONTROLF_UNIFORM & pmxctrl->fdwControl) 
775                                                        cChannels = 1; 
776                                                pbool = (LPMIXERCONTROLDETAILS_BOOLEAN) malloc(cChannels * sizeof(
777                                                        MIXERCONTROLDETAILS_BOOLEAN));
778
779                                                mxcd.cbStruct = sizeof(mxcd);
780                                                mxcd.dwControlID = pmxctrl->dwControlID;
781                                                mxcd.cChannels = cChannels;
782                                                mxcd.hwndOwner = (HWND)0;
783                                                mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
784                                                mxcd.paDetails = (LPVOID) pbool;
785
786                                                mixerGetControlDetails((HMIXEROBJ)dwMixerHandle, &mxcd, 
787                                                        MIXER_SETCONTROLDETAILSF_VALUE); 
788                                                /* Unmute the microphone line (for both channels) */
789                                                pbool[0].fValue = pbool[cChannels - 1].fValue = val; /* 0 -> unmute; */
790                                                mixerSetControlDetails((HMIXEROBJ)dwMixerHandle, &mxcd, 
791                                                        MIXER_SETCONTROLDETAILSF_VALUE); 
792                                                free(pmxctrl); 
793                                                free(pbool); 
794                                        } 
795                                        else 
796                                                free(pmxctrl); 
797                                }
798                        }
799                        mixerClose( (HMIXER)dwMixerHandle );
800                        if (mr != MMSYSERR_NOERROR)
801                        {
802                                ms_error("winsndcard_set_control: mixerClose failed. (0x%x)", mr);
803                                return -1;
804                        }
805                        return 0;
806
807                case MS_SND_CARD_MASTER_MUTE:
808                case MS_SND_CARD_PLAYBACK_MUTE:
809                        {
810                                bMute.fValue = (val>0);
811
812                                mr = mixerGetID( (HMIXEROBJ)waveout_devid, &uMixerID, MIXER_OBJECTF_WAVEOUT );
813                                if ( mr != MMSYSERR_NOERROR )
814                                {
815                                        ms_error("winsndcard_set_control: mixerGetID failed. (0x%x)", mr);
816                                        return -1;
817                                }
818                                mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
819                                if ( mr != MMSYSERR_NOERROR )
820                                {
821                                        mixerClose( (HMIXER)dwMixerHandle );
822                                        ms_error("winsndcard_set_control: mixerOpen failed. (0x%x)", mr);
823                                        return -1;
824                                }
825                                memset( &MixerLine, 0, sizeof(MIXERLINE) );
826                                MixerLine.cbStruct = sizeof(MIXERLINE);
827                                if (MS_SND_CARD_MASTER_MUTE==e)
828                                        MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
829                                else
830                                        MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
831                                mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE );
832                                if ( mr != MMSYSERR_NOERROR )
833                                {
834                                        mixerClose( (HMIXER)dwMixerHandle );
835                                        ms_error("winsndcard_set_control: mixerSetControlDetails failed. (0x%x)", mr);
836                                        return -1;
837                                }
838
839                                /* ms_message("Name: %s\n", MixerLine.szName); */
840                                /* ms_message("Source Line: %d\n", MixerLine.dwSource); */
841                                /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
842
843                                mlc.cbStruct = sizeof(MIXERLINECONTROLS);
844                                mlc.dwLineID = MixerLine.dwLineID;
845                                mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE; //MIXERCONTROL_CONTROLTYPE_VOLUME;
846                                mlc.cControls = 1;
847                                mlc.pamxctrl = &mc;
848                                mlc.cbmxctrl = sizeof(MIXERCONTROL);
849                                mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle, 
850                                        &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
851
852                                mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
853                                mcd.hwndOwner = 0;
854                                mcd.dwControlID = mc.dwControlID;
855                                mcd.paDetails = &bMute;
856                                mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
857                                mcd.cChannels = 1;
858                                mr = mixerSetControlDetails((HMIXEROBJ)dwMixerHandle, 
859                                        &mcd, MIXER_SETCONTROLDETAILSF_VALUE);
860
861                                if (mr != MMSYSERR_NOERROR)
862                                {
863                                        ms_error("winsndcard_set_control: mixerSetControlDetails failed. (0x%x)", mr);
864                                        return -1;
865                                }
866                                return 0;
867                        }
868                        break;
869                default:
870                        ms_warning("winsndcard_set_control: unsupported command.");
871        }
872        return -1;
873}
874
875static int winsnddscard_get_control(MSSndCard *card, MSSndCardControlElem e){
876        WinSndDsCard *d=(WinSndDsCard*)card->data;
877        return -1;
878}
879
880static void winsnddscard_init(MSSndCard *card){
881        WinSndDsCard *c=(WinSndDsCard *)ms_new(WinSndDsCard,1);
882        c->removed=0;
883        card->data=c;
884}
885
886static void winsnddscard_uninit(MSSndCard *card){
887        ms_free(card->data);
888}
889
890static void winsnddscard_detect(MSSndCardManager *m);
891static  MSSndCard *winsnddscard_dup(MSSndCard *obj);
892static void winsnddscard_unload(MSSndCardManager *m);
893
894MSSndCardDesc winsndds_card_desc={
895        "DirectSound",
896        winsnddscard_detect,
897        winsnddscard_init,
898        winsnddscard_set_level,
899        winsnddscard_get_level,
900        winsnddscard_set_source,
901        winsnddscard_set_control,
902        NULL,
903        ms_winsndds_read_new,
904        ms_winsndds_write_new,
905        winsnddscard_uninit,
906        winsnddscard_dup,
907        winsnddscard_unload
908};
909
910static  MSSndCard *winsnddscard_dup(MSSndCard *obj){
911        MSSndCard *card=ms_snd_card_new(&winsndds_card_desc);
912        card->name=ms_strdup(obj->name);
913        card->data=ms_new(WinSndDsCard,1);
914        memcpy(card->data,obj->data,sizeof(WinSndDsCard));
915        return card;
916}
917
918static MSSndCard *winsnddscard_new(const char *name, LPGUID lpguid, int in_dev, int out_dev, unsigned cap){
919        MSSndCard *card=ms_snd_card_new(&winsndds_card_desc);
920        WinSndDsCard *d=(WinSndDsCard*)card->data;
921        card->name=ms_strdup(name);
922        d->in_devid=in_dev;
923        d->out_devid=out_dev;
924        card->capabilities=cap;
925        memset(&d->out_guid, 0, sizeof(GUID));
926        memset(&d->in_guid, 0, sizeof(GUID));
927        if (out_dev!=-1)
928        {
929                if (lpguid!=NULL)
930                        memcpy(&d->out_guid, lpguid, sizeof(GUID));
931        }
932        else
933        {
934                if (lpguid!=NULL)
935                        memcpy(&d->in_guid, lpguid, sizeof(GUID));
936        }
937        return card;
938}
939
940static void add_or_update_card(MSSndCardManager *m, const char *name, LPGUID lpguid, int indev, int outdev, unsigned int capability){
941        MSSndCard *card;
942        const MSList *elem=ms_snd_card_manager_get_list(m);
943        for(;elem!=NULL;elem=elem->next){
944                card=(MSSndCard*)elem->data;
945                if (strcmp(card->desc->driver_type, winsndds_card_desc.driver_type)==0
946                        && strcmp(card->name,name)==0){
947                        /*update already entered card */
948                        WinSndDsCard *d=(WinSndDsCard*)card->data;
949                        card->capabilities|=capability;
950                        if (indev!=-1) 
951                                d->in_devid=indev;
952                        if (outdev!=-1)
953                                d->out_devid=outdev;
954
955                        if (outdev!=-1)
956                        {
957                                if (lpguid!=NULL)
958                                        memcpy(&d->out_guid, lpguid, sizeof(GUID));
959                                else
960                                        memset(&d->out_guid, 0, sizeof(GUID));
961                        }
962                        if (indev!=-1)
963                        {
964                                if (lpguid!=NULL)
965                                        memcpy(&d->in_guid, lpguid, sizeof(GUID));
966                                else
967                                        memset(&d->in_guid, 0, sizeof(GUID));
968                        }
969                        /* if (d->in_devid!=-1 && d->out_devid!=-1) */
970                        /*      ms_message("DS: new full duplex card %s", name); */
971                        d->removed=0;
972                        return;
973                }
974        }
975        /* add this new card:*/
976        ms_snd_card_manager_add_card(m,winsnddscard_new(name,lpguid, indev,outdev,capability));
977}
978
979static BOOL CALLBACK enumerate_capture_devices_callback(LPGUID lpGUID,
980                                                                                                                LPCWSTR lpszDesc,
981                                                                                                                LPCWSTR lpszDrvName,
982                                                                                                                LPVOID lpContext )
983{
984        MSSndCardManager *m = (MSSndCardManager*)lpContext;
985        static int dev_index=0;
986
987        if ( lpGUID == NULL ) /* primary device */
988        {
989                char szName[256];
990                wchar_t snd_card_name[256];
991                swprintf(snd_card_name, 256, L"%s", lpszDesc);
992                WideCharToMultiByte(CP_UTF8,0,snd_card_name,-1,szName,256,0,0);
993
994                add_or_update_card(m,szName,lpGUID,dev_index,-1,MS_SND_CARD_CAP_CAPTURE);
995                dev_index++;
996        }
997        else
998        {
999                char szName[256];
1000                wchar_t snd_card_name[256];
1001                swprintf(snd_card_name, 256, L"%s", lpszDesc);
1002                WideCharToMultiByte(CP_UTF8,0,snd_card_name,-1,szName,256,0,0);
1003
1004                add_or_update_card(m,szName,lpGUID,dev_index,-1,MS_SND_CARD_CAP_CAPTURE);
1005                dev_index++;
1006        }
1007
1008        return true;
1009}
1010
1011static BOOL CALLBACK enumerate_playback_devices_callback(LPGUID lpGUID,
1012                                                                                                                 LPCWSTR lpszDesc,
1013                                                                                                                 LPCWSTR lpszDrvName,
1014                                                                                                                 LPVOID lpContext )
1015{
1016        MSSndCardManager *m = (MSSndCardManager*)lpContext;
1017        static int dev_index=0;
1018
1019        if ( lpGUID == NULL ) /* primary device */
1020        {
1021                char szName[256];
1022                wchar_t snd_card_name[256];
1023                swprintf(snd_card_name, 256, L"%s", lpszDesc);
1024                WideCharToMultiByte(CP_UTF8,0,snd_card_name,-1,szName,256,0,0);
1025
1026                add_or_update_card(m,szName,lpGUID,-1,dev_index,MS_SND_CARD_CAP_PLAYBACK);
1027                dev_index++;
1028        }
1029        else
1030        {
1031                char szName[256];
1032                wchar_t snd_card_name[256];
1033                swprintf(snd_card_name, 256, L"%s", lpszDesc);
1034                WideCharToMultiByte(CP_UTF8,0,snd_card_name,-1,szName,256,0,0);
1035
1036                add_or_update_card(m,szName,lpGUID,-1,dev_index,MS_SND_CARD_CAP_PLAYBACK);
1037                dev_index++;
1038        }
1039
1040        return true;
1041}
1042
1043static void _winsnddscard_detect(MSSndCardManager *m){
1044        MMRESULT mr = NOERROR;
1045
1046        if (ms_lib_instance==NULL)
1047        {
1048                ms_lib_instance = LoadLibrary("dsound.dll");
1049                if( ms_lib_instance == NULL )
1050                {
1051                        /* error */
1052                        ms_debug("winsnddscard_detect: no support for dsound (missing dsound.dll)\n");
1053                        return;
1054                }
1055
1056                ms_DllGetClassObject =(HRESULT (WINAPI *)(REFCLSID, REFIID , LPVOID *))
1057                        GetProcAddress( ms_lib_instance, "DllGetClassObject" );
1058
1059                ms_DirectSoundCreate =(HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN))
1060                        GetProcAddress( ms_lib_instance, "DirectSoundCreate" );
1061
1062                ms_DirectSoundEnumerate =(HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID))
1063                        GetProcAddress( ms_lib_instance, "DirectSoundEnumerateW" );
1064
1065                ms_DirectSoundCaptureCreate =(HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN))
1066                        GetProcAddress( ms_lib_instance, "DirectSoundCaptureCreate" );
1067
1068                ms_DirectSoundCaptureEnumerate =(HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID))
1069                        GetProcAddress( ms_lib_instance, "DirectSoundCaptureEnumerateW" );
1070
1071                ms_DirectSoundFullDuplexCreate =(HRESULT (WINAPI *)(LPCGUID , LPCGUID ,
1072                        LPCDSCBUFFERDESC , LPCDSBUFFERDESC , HWND ,
1073                        DWORD , LPDIRECTSOUNDFULLDUPLEX* , LPDIRECTSOUNDCAPTUREBUFFER8 *,
1074                        LPDIRECTSOUNDBUFFER8 *, LPUNKNOWN))
1075                        GetProcAddress( ms_lib_instance, "DirectSoundFullDuplexCreate" );
1076
1077                if( ms_DllGetClassObject == NULL ||
1078                        ms_DirectSoundCreate == NULL ||
1079                        ms_DirectSoundEnumerate == NULL ||
1080                        ms_DirectSoundCaptureEnumerate == NULL ||
1081                        ms_DirectSoundCaptureCreate == NULL )
1082                {
1083                        /* error */
1084                        ms_debug("winsnddscard_detect: no support for dsound\n");
1085                        return;
1086                }
1087        }
1088
1089        ms_DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)enumerate_capture_devices_callback, (void *)m );
1090        ms_DirectSoundEnumerate( (LPDSENUMCALLBACK)enumerate_playback_devices_callback, (void *)m );
1091}
1092
1093static void deactivate_removed_cards(MSSndCardManager *m){
1094        MSSndCard *card;
1095        const MSList *elem=ms_snd_card_manager_get_list(m);
1096        for(;elem!=NULL;elem=elem->next){
1097                card=(MSSndCard*)elem->data;
1098                if (strcmp(card->desc->driver_type, winsndds_card_desc.driver_type)==0){
1099                        /*mark all cards as potentially removed, detect will check them immediately after */
1100                        WinSndDsCard *d=(WinSndDsCard*)card->data;
1101                        if (d->removed) card->capabilities=0;
1102                }
1103        }
1104}
1105
1106static void mark_as_removed(MSSndCardManager *m){
1107        MSSndCard *card;
1108        const MSList *elem=ms_snd_card_manager_get_list(m);
1109        for(;elem!=NULL;elem=elem->next){
1110                card=(MSSndCard*)elem->data;
1111                if (strcmp(card->desc->driver_type, winsndds_card_desc.driver_type)==0){
1112                        /*mark all cards as potentially removed, detect will check them immediately after */
1113                        WinSndDsCard *d=(WinSndDsCard*)card->data;
1114                        d->removed=1;
1115                }
1116        }
1117}
1118
1119static ms_thread_t poller_thread=NULL;
1120static bool_t poller_running=TRUE;
1121
1122static void * new_device_polling_thread(void *ignore){
1123        MSSndCardManager *m;
1124        /*check for new devices every 2 seconds*/
1125        while(poller_running){
1126                ms_sleep(5);
1127                if (poller_running){
1128                        m=ms_snd_card_manager_get();
1129                        if(!m) break;
1130                        mark_as_removed(m);
1131                        _winsnddscard_detect(m);
1132                        deactivate_removed_cards(m);
1133                }
1134        }
1135        return NULL;
1136}
1137
1138static void stop_poller(){
1139        poller_running=FALSE;
1140        ms_thread_join(poller_thread,NULL);
1141        poller_thread=NULL;
1142}
1143
1144static void winsnddscard_unload(MSSndCardManager *m){
1145        stop_poller();
1146}
1147
1148static void winsnddscard_detect(MSSndCardManager *m){
1149        _winsnddscard_detect(m);
1150        if (poller_thread==NULL)
1151                ms_thread_create(&poller_thread,NULL,new_device_polling_thread,NULL);
1152}
1153
1154typedef struct WinSndDs{
1155        int dev_id;
1156        GUID in_guid;
1157        GUID out_guid;
1158
1159        ms_thread_t thread;
1160        ms_mutex_t thread_lock;
1161        ms_cond_t thread_cond;
1162        bool_t thread_running;
1163
1164        MSBufferizer output_buff;
1165        LPDIRECTSOUNDFULLDUPLEX lpDirectSoundFullDuplex;
1166        LPDIRECTSOUND lpDirectSound;
1167        LPDIRECTSOUNDBUFFER  lpDirectSoundOutputBuffer;
1168        double               dsw_framesWritten;
1169        UINT                 writeOffset;      /* last read position */
1170
1171        LPDIRECTSOUNDCAPTURE lpDirectSoundCapture;
1172        LPDIRECTSOUNDCAPTUREBUFFER  lpDirectSoundInputBuffer;
1173        UINT                 readOffset;      /* last read position */
1174
1175        int              framesPerDSBuffer;
1176
1177        WAVEFORMATEX wfx;
1178        queue_t rq;
1179        ms_mutex_t mutex;
1180        uint64_t bytes_read;
1181        unsigned int nbufs_playing;
1182
1183        int32_t stat_input;
1184        int32_t stat_output;
1185        int32_t stat_notplayed;
1186
1187}WinSndDs;
1188
1189void * 
1190winsndds_read_thread(void *arg)
1191{
1192        WinSndDs *d=(WinSndDs*)arg;
1193
1194        ms_mutex_lock(&d->thread_lock);
1195        ms_cond_signal(&d->thread_cond);
1196        ms_mutex_unlock(&d->thread_lock);
1197
1198        while(d->thread_running)
1199        {
1200                HRESULT hr;
1201                DWORD capturePos;
1202                DWORD readPos;
1203                long filled = 0;
1204                long bytesFilled = 0;
1205                LPBYTE            lpInBuf1 = NULL;
1206                LPBYTE            lpInBuf2 = NULL;
1207                DWORD             dwInSize1 = 0;
1208                DWORD             dwInSize2 = 0;
1209
1210                hr = IDirectSoundCaptureBuffer_GetCurrentPosition( d->lpDirectSoundInputBuffer,
1211                        &capturePos, &readPos );
1212                if( hr != DS_OK )
1213                {
1214                        continue;
1215                }
1216
1217                filled = readPos - d->readOffset;
1218                if( filled < 0 ) filled += d->framesPerDSBuffer;
1219                bytesFilled = filled;
1220
1221                hr = IDirectSoundCaptureBuffer_Lock ( d->lpDirectSoundInputBuffer,
1222                        d->readOffset, bytesFilled,
1223                        (void **) &lpInBuf1, &dwInSize1,
1224                        (void **) &lpInBuf2, &dwInSize2, 0);
1225                if (hr != DS_OK)
1226                {
1227                        Sleep(10);
1228                        continue;
1229                }
1230
1231                if (dwInSize1==0)
1232                {
1233                        Sleep(10);
1234                }
1235                else if (dwInSize1>=bytesFilled)
1236                {
1237                        mblk_t *m=allocb(bytesFilled,0);
1238                        memcpy(m->b_rptr, lpInBuf1, bytesFilled);
1239                        m->b_wptr+=bytesFilled;
1240                        ms_mutex_lock(&d->mutex);
1241                        putq(&d->rq,m);
1242                        ms_mutex_unlock(&d->mutex);
1243                        d->bytes_read+=bytesFilled;
1244                        /* ms_message("bytesFilled=%i\n",bytesFilled); */
1245                }
1246                else
1247                {
1248                        mblk_t *m=allocb(bytesFilled,0);
1249                        memcpy(m->b_rptr, lpInBuf1, dwInSize1);
1250                        memcpy(m->b_rptr+dwInSize1, lpInBuf2, dwInSize2);
1251                        m->b_wptr+=bytesFilled;
1252                        ms_mutex_lock(&d->mutex);
1253                        putq(&d->rq,m);
1254                        ms_mutex_unlock(&d->mutex);
1255                        d->bytes_read+=bytesFilled;
1256                        /* ms_message("bytesFilled=%i\n",bytesFilled); */
1257                }
1258
1259                d->readOffset = (d->readOffset + bytesFilled) % d->framesPerDSBuffer;
1260
1261                IDirectSoundCaptureBuffer_Unlock( d->lpDirectSoundInputBuffer,
1262                        lpInBuf1, dwInSize1, lpInBuf2, dwInSize2);
1263        }
1264
1265        ms_mutex_lock(&d->thread_lock);
1266        ms_cond_signal(&d->thread_cond);
1267        ms_mutex_unlock(&d->thread_lock);
1268        ms_thread_exit(NULL);
1269        return NULL;
1270}
1271
1272static void winsndds_apply_settings(WinSndDs *d){
1273        d->wfx.nBlockAlign=d->wfx.nChannels*d->wfx.wBitsPerSample/8;
1274        d->wfx.nAvgBytesPerSec=d->wfx.nSamplesPerSec*d->wfx.nBlockAlign;
1275}
1276
1277static uint64_t winsndds_get_cur_time( void *data){
1278        WinSndDs *d=(WinSndDs*)data;
1279        uint64_t curtime=(d->bytes_read*1000)/(uint64_t)d->wfx.nAvgBytesPerSec;
1280        return curtime;
1281}
1282
1283
1284static void winsndds_init(MSFilter *f){
1285        WinSndDs *d=(WinSndDs *)ms_new0(WinSndDs,1);
1286        d->wfx.wFormatTag = WAVE_FORMAT_PCM;
1287        d->wfx.cbSize = 0;
1288        d->wfx.nAvgBytesPerSec = 16000;
1289        d->wfx.nBlockAlign = 2;
1290        d->wfx.nChannels = 1;
1291        d->wfx.nSamplesPerSec = 8000;
1292        d->wfx.wBitsPerSample = 16;
1293        qinit(&d->rq);
1294        ms_mutex_init(&d->mutex,NULL);
1295        f->data=d;
1296
1297        d->stat_input=0;
1298        d->stat_output=0;
1299        d->stat_notplayed=0;
1300
1301        d->framesPerDSBuffer = 320 * (8000 / 1000);
1302
1303        d->thread = NULL;
1304        ms_mutex_init(&d->thread_lock,NULL);
1305        ms_cond_init(&d->thread_cond,NULL);
1306        d->thread_running = FALSE;
1307
1308        ms_bufferizer_init(&d->output_buff);
1309}
1310
1311static void winsndds_uninit(MSFilter *f){
1312        WinSndDs *d=(WinSndDs*)f->data;
1313
1314        d->thread = NULL;
1315        d->thread_running = FALSE;
1316        ms_cond_destroy(&d->thread_cond);
1317        ms_mutex_destroy(&d->thread_lock);
1318        ms_bufferizer_uninit(&d->output_buff);
1319
1320        flushq(&d->rq,0);
1321        ms_mutex_destroy(&d->mutex);
1322        ms_free(f->data);
1323}
1324
1325static void winsndds_read_preprocess(MSFilter *f){
1326        WinSndDs *d=(WinSndDs*)f->data;
1327        DSCBUFFERDESC  captureDesc;
1328        HRESULT hr;
1329
1330        d->stat_input=0;
1331        d->stat_output=0;
1332        d->stat_notplayed=0;
1333
1334        d->framesPerDSBuffer = d->wfx.nAvgBytesPerSec/4;
1335        winsndds_apply_settings(d);
1336        ms_message("full duplex and echo canceller! (%x)" ,d->lpDirectSound);
1337        ms_DirectSoundCaptureCreate( &d->in_guid, &d->lpDirectSoundCapture, NULL );
1338
1339        ZeroMemory(&captureDesc, sizeof(DSCBUFFERDESC));
1340        captureDesc.dwSize = sizeof(DSCBUFFERDESC);
1341        captureDesc.dwFlags =  0;
1342        captureDesc.dwBufferBytes = d->framesPerDSBuffer;
1343        captureDesc.lpwfxFormat = &d->wfx;
1344
1345        if ((hr = IDirectSoundCapture_CreateCaptureBuffer( d->lpDirectSoundCapture,
1346                &captureDesc, &d->lpDirectSoundInputBuffer, NULL)) != DS_OK)
1347        {
1348                return;
1349        }
1350        d->readOffset = 0;
1351
1352        hr = IDirectSoundCaptureBuffer_Start( d->lpDirectSoundInputBuffer, DSCBSTART_LOOPING );
1353
1354        ms_mutex_lock(&f->ticker->lock);
1355        ms_ticker_set_time_func(f->ticker,winsndds_get_cur_time,d);
1356        ms_mutex_unlock(&f->ticker->lock);
1357
1358        d->thread_running=TRUE;
1359        ms_thread_create(&d->thread,NULL,winsndds_read_thread,d);
1360        ms_mutex_lock(&d->thread_lock);
1361        ms_cond_wait(&d->thread_cond,&d->thread_lock);
1362        ms_mutex_unlock(&d->thread_lock);
1363
1364        return;
1365}
1366
1367static void winsndds_read_postprocess(MSFilter *f){
1368        WinSndDs *d=(WinSndDs*)f->data;
1369
1370        ms_mutex_lock(&d->thread_lock);
1371        d->thread_running=FALSE;
1372        ms_cond_wait(&d->thread_cond,&d->thread_lock);
1373        ms_mutex_unlock(&d->thread_lock);
1374        ms_thread_join(d->thread,NULL);
1375
1376        ms_mutex_lock(&f->ticker->lock);
1377        ms_ticker_set_time_func(f->ticker,NULL,NULL);
1378        ms_mutex_unlock(&f->ticker->lock);
1379
1380        if( d->lpDirectSoundInputBuffer )
1381        {
1382                IDirectSoundCaptureBuffer_Stop( d->lpDirectSoundInputBuffer );
1383                IDirectSoundCaptureBuffer_Release( d->lpDirectSoundInputBuffer );
1384                d->lpDirectSoundInputBuffer = NULL;
1385        }
1386
1387        if( d->lpDirectSoundCapture )
1388        {
1389                IDirectSoundCapture_Release( d->lpDirectSoundCapture );
1390                d->lpDirectSoundCapture = NULL;
1391        }
1392
1393        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);
1394        flushq(&d->rq,0);
1395}
1396
1397static void winsndds_read_process(MSFilter *f){
1398        WinSndDs *d=(WinSndDs*)f->data;
1399        mblk_t *m;
1400
1401        ms_mutex_lock(&d->mutex);
1402        while((m=getq(&d->rq))!=NULL){
1403                ms_queue_put(f->outputs[0],m);
1404        }
1405        ms_mutex_unlock(&d->mutex);
1406}
1407
1408static void winsndds_write_preprocess(MSFilter *f){
1409        WinSndDs *d=(WinSndDs*)f->data;
1410
1411        DWORD          dwDataLen;
1412        DWORD          playCursor;
1413        HWND           hWnd;
1414        HRESULT        hr;
1415        LPDIRECTSOUNDBUFFER pPrimaryBuffer;
1416        DSBUFFERDESC   primaryDesc;
1417        DSBUFFERDESC   secondaryDesc;
1418        unsigned char* pDSBuffData;
1419        DWORD outputBufferWriteOffsetBytes;
1420
1421        MSList *filters=NULL;
1422        MSFilter *f_capture_filter=NULL;
1423        WinSndDs *d_capture_filter=NULL;
1424
1425        filters=ms_filter_find_neighbours(f);
1426        if (filters!=NULL)
1427        {
1428                MSList *it;
1429                /* search for another winsndds filter */
1430                for(it=filters;it!=NULL;it=it->next)
1431                {
1432                        f_capture_filter = (MSFilter*)it->data;
1433                        if (f_capture_filter->desc->id == MS_WINSNDDS_READ_ID)
1434                        {
1435                                /* found */
1436                                d_capture_filter=(WinSndDs*)f_capture_filter->data;
1437                                break;
1438                        }
1439                        f_capture_filter=NULL;
1440                }
1441                ms_list_free(filters);
1442        }
1443
1444        d->stat_input=0;
1445        d->stat_output=0;
1446        d->stat_notplayed=0;
1447
1448        d->framesPerDSBuffer = d->wfx.nAvgBytesPerSec/4;
1449        winsndds_apply_settings(d);
1450
1451        if (d_capture_filter!=NULL
1452                && d_capture_filter->lpDirectSoundCapture!=NULL
1453                && IsEqualIID(d_capture_filter->in_guid, d->in_guid))
1454        {
1455                DSCBUFFERDESC captureDesc;
1456
1457                winsndds_read_postprocess(f_capture_filter);
1458
1459                DSCEFFECTDESC dscfx[1];
1460                ZeroMemory( &dscfx[0], sizeof( DSCEFFECTDESC ) );
1461                dscfx[0].dwSize = sizeof( DSCEFFECTDESC );
1462                dscfx[0].dwFlags = DSCFX_LOCSOFTWARE ;
1463                dscfx[0].guidDSCFXClass = GUID_DSCFX_CLASS_AEC;
1464                dscfx[0].guidDSCFXInstance = GUID_DSCFX_MS_AEC;
1465                dscfx[0].dwReserved1 = 0;
1466                dscfx[0].dwReserved2 = 0;
1467
1468                d_capture_filter->framesPerDSBuffer = d_capture_filter->wfx.nAvgBytesPerSec/4;
1469                winsndds_apply_settings(d_capture_filter);
1470
1471                ZeroMemory(&captureDesc, sizeof(DSCBUFFERDESC));
1472                captureDesc.dwSize = sizeof(DSCBUFFERDESC);
1473                captureDesc.dwFlags =  DSCBCAPS_CTRLFX;
1474                captureDesc.dwBufferBytes = d_capture_filter->framesPerDSBuffer;
1475                captureDesc.lpwfxFormat = &d_capture_filter->wfx;
1476                captureDesc.dwFXCount = 1;
1477                captureDesc.lpDSCFXDesc = dscfx;
1478
1479                ZeroMemory(&secondaryDesc, sizeof(DSBUFFERDESC));
1480                secondaryDesc.dwSize = sizeof(DSBUFFERDESC);
1481                secondaryDesc.dwFlags =  DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2
1482                        | DSBCAPS_LOCSOFTWARE;
1483                secondaryDesc.dwBufferBytes = d->framesPerDSBuffer;
1484                secondaryDesc.lpwfxFormat = &d->wfx;
1485
1486                hWnd = GetDesktopWindow();
1487                hr = ms_DirectSoundFullDuplexCreate(&d_capture_filter->in_guid,
1488                        &d->out_guid,
1489                        &captureDesc,
1490                        &secondaryDesc,
1491                        hWnd,
1492                        DSSCL_NORMAL,
1493                        &d->lpDirectSoundFullDuplex,
1494                        (LPDIRECTSOUNDCAPTUREBUFFER8*)&d_capture_filter->lpDirectSoundInputBuffer,
1495                        (LPDIRECTSOUNDBUFFER8*)&d->lpDirectSoundOutputBuffer,
1496                        NULL);
1497
1498                if (hr!=DS_OK)
1499                {
1500                        ms_message("full duplex and echo canceller: disabled!");
1501                        captureDesc.dwFlags =  0;
1502                        captureDesc.dwFXCount = 0;
1503                        captureDesc.lpDSCFXDesc = NULL;
1504
1505                        hr = ms_DirectSoundFullDuplexCreate(&d_capture_filter->in_guid,
1506                                &d->out_guid,
1507                                &captureDesc,
1508                                &secondaryDesc,
1509                                hWnd,
1510                                DSSCL_NORMAL,
1511                                &d->lpDirectSoundFullDuplex,
1512                                (LPDIRECTSOUNDCAPTUREBUFFER8*)&d_capture_filter->lpDirectSoundInputBuffer,
1513                                (LPDIRECTSOUNDBUFFER8*)&d->lpDirectSoundOutputBuffer,
1514                                NULL);
1515                }
1516                if (hr!=DS_OK)
1517                {
1518                        ms_message("full duplex and echo canceller: disabled!");
1519                        return;
1520                }
1521                ms_message("full duplex and echo canceller: activated!");
1522
1523                d_capture_filter->readOffset = 0;
1524
1525                hr = IDirectSoundCaptureBuffer_Start( d_capture_filter->lpDirectSoundInputBuffer, DSCBSTART_LOOPING );
1526
1527                ms_mutex_lock(&f->ticker->lock);
1528                ms_ticker_set_time_func(f_capture_filter->ticker,winsndds_get_cur_time,d_capture_filter);
1529                ms_mutex_unlock(&f->ticker->lock);
1530
1531                d_capture_filter->thread_running=TRUE;
1532                ms_thread_create(&d_capture_filter->thread,NULL,winsndds_read_thread,d_capture_filter);
1533                ms_mutex_lock(&d_capture_filter->thread_lock);
1534                ms_cond_wait(&d_capture_filter->thread_cond,&d_capture_filter->thread_lock);
1535                ms_mutex_unlock(&d_capture_filter->thread_lock);
1536        }
1537        else
1538        {
1539                ms_DirectSoundCreate( &d->out_guid, &d->lpDirectSound, NULL );
1540
1541
1542                hWnd = GetDesktopWindow();
1543                if ((hr = IDirectSound_SetCooperativeLevel( d->lpDirectSound,
1544                        hWnd, DSSCL_PRIORITY)) != DS_OK) //DSSCL_EXCLUSIVE)) != DS_OK)
1545                {
1546                        return ;
1547                }
1548
1549                ZeroMemory(&primaryDesc, sizeof(DSBUFFERDESC));
1550                primaryDesc.dwSize        = sizeof(DSBUFFERDESC);
1551                primaryDesc.dwFlags       = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_PRIMARYBUFFER;
1552                primaryDesc.dwBufferBytes = 0;
1553                primaryDesc.lpwfxFormat   = NULL;
1554                if ((hr = IDirectSound_CreateSoundBuffer( d->lpDirectSound,
1555                        &primaryDesc, &pPrimaryBuffer, NULL)) != DS_OK)
1556                {
1557                        return ;
1558                }
1559
1560                if ((hr = IDirectSoundBuffer_SetFormat( pPrimaryBuffer, &d->wfx)) != DS_OK)
1561                {
1562                        return ;
1563                }
1564                IDirectSoundBuffer_Release(pPrimaryBuffer);
1565
1566                ZeroMemory(&secondaryDesc, sizeof(DSBUFFERDESC));
1567                secondaryDesc.dwSize = sizeof(DSBUFFERDESC);
1568                secondaryDesc.dwFlags =  DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
1569                secondaryDesc.dwBufferBytes = d->framesPerDSBuffer;
1570                secondaryDesc.lpwfxFormat = &d->wfx;
1571                if ((hr = IDirectSound_CreateSoundBuffer( d->lpDirectSound,
1572                        &secondaryDesc, &d->lpDirectSoundOutputBuffer, NULL)) != DS_OK)
1573                {
1574                        return ;
1575                }
1576        }
1577
1578        if ((hr = IDirectSoundBuffer_Lock( d->lpDirectSoundOutputBuffer, 0,
1579                d->framesPerDSBuffer,
1580                (LPVOID*)&pDSBuffData,
1581                &dwDataLen, NULL, 0, 0)) != DS_OK)
1582        {
1583                return ;
1584        }
1585
1586        ZeroMemory(pDSBuffData, dwDataLen);
1587        if ((hr = IDirectSoundBuffer_Unlock( d->lpDirectSoundOutputBuffer,
1588                pDSBuffData, dwDataLen, NULL, 0)) != DS_OK)
1589        {
1590                return ;
1591        }
1592
1593        hr = IDirectSoundBuffer_GetCurrentPosition( d->lpDirectSoundOutputBuffer,
1594                &playCursor, &outputBufferWriteOffsetBytes );
1595        if( hr != DS_OK )
1596        {
1597                return ;
1598        }
1599
1600        hr = IDirectSoundBuffer_SetCurrentPosition( d->lpDirectSoundOutputBuffer, 0 );
1601        if( hr != DS_OK )
1602        {
1603                return ;
1604        }
1605
1606        hr = IDirectSoundBuffer_Play( d->lpDirectSoundOutputBuffer, 0, 0, DSBPLAY_LOOPING);
1607        if( hr != DS_OK )
1608        {
1609                return ;
1610        }
1611        d->writeOffset=-1;
1612
1613        return ;
1614}
1615
1616static void winsndds_write_postprocess(MSFilter *f){
1617        WinSndDs *d=(WinSndDs*)f->data;
1618
1619        if( d->lpDirectSoundOutputBuffer )
1620        {
1621                IDirectSoundBuffer_Stop( d->lpDirectSoundOutputBuffer );
1622                IDirectSoundBuffer_Release( d->lpDirectSoundOutputBuffer );
1623                d->lpDirectSoundOutputBuffer = NULL;
1624        }
1625
1626        if( d->lpDirectSound )
1627        {
1628                IDirectSound_Release( d->lpDirectSound );
1629                d->lpDirectSound = NULL;
1630        }
1631
1632        if( d->lpDirectSoundFullDuplex )
1633        {
1634                IDirectSoundFullDuplex_Release( d->lpDirectSoundFullDuplex );
1635                d->lpDirectSoundFullDuplex = NULL;
1636        }
1637
1638        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);
1639        d->writeOffset=-1;
1640}
1641
1642static void winsndds_write_process(MSFilter *f){
1643        WinSndDs *d=(WinSndDs*)f->data;
1644        int discarded=0;
1645        DWORD dwStatus;
1646        HRESULT hr;
1647
1648        if (d->lpDirectSoundOutputBuffer==NULL) {
1649                ms_queue_flush(f->inputs[0]);
1650                return;
1651        }
1652
1653        ms_bufferizer_put_from_queue(&d->output_buff,f->inputs[0]);
1654
1655        if (d->writeOffset==-1)
1656        {
1657                if (ms_bufferizer_get_avail(&d->output_buff)>=d->framesPerDSBuffer)
1658                {
1659                        DWORD playCursor;
1660                        DWORD outputBufferWriteOffsetBytes;
1661                        IDirectSoundBuffer_GetCurrentPosition( d->lpDirectSoundOutputBuffer,
1662                                &playCursor, &outputBufferWriteOffsetBytes );
1663                        d->writeOffset = outputBufferWriteOffsetBytes;
1664                }
1665                else
1666                        return;
1667        }
1668
1669        DWORD current_playOffset;
1670        long msize_max = 0;
1671        DWORD currentWriteOffset;
1672        IDirectSoundBuffer_GetCurrentPosition( d->lpDirectSoundOutputBuffer,
1673                &current_playOffset, &currentWriteOffset );
1674
1675        msize_max = current_playOffset - currentWriteOffset;
1676        if( msize_max < 0 ) msize_max += d->framesPerDSBuffer;
1677
1678        /* write from d->writeOffset up to current_playOffset */
1679        msize_max=current_playOffset-d->writeOffset;
1680        if( msize_max < 0 ) msize_max += d->framesPerDSBuffer;
1681
1682        //ms_message("DS information: last_writeOffset=%i current_playOffset=%i current_writeOffset=%i max_writable=%i",
1683        //      d->writeOffset, current_playOffset, currentWriteOffset, msize_max);
1684
1685        hr = IDirectSoundBuffer_GetStatus (d->lpDirectSoundOutputBuffer, &dwStatus);
1686        if (dwStatus & DSBSTATUS_BUFFERLOST) {
1687                hr = IDirectSoundBuffer_Restore (d->lpDirectSoundOutputBuffer);
1688                d->writeOffset = 0;
1689                ms_message("DSBSTATUS_BUFFERLOST: restoring buffer");
1690        }
1691
1692        if (msize_max==0)
1693                return;
1694        int msize=d->framesPerDSBuffer/4;
1695        if (msize>msize_max)
1696                msize = msize_max;
1697        while (ms_bufferizer_get_avail(&d->output_buff)>=msize)
1698        {
1699                LPBYTE lpOutBuf1 = NULL;
1700                LPBYTE lpOutBuf2 = NULL;
1701                DWORD  dwOutSize1 = 0;
1702                DWORD  dwOutSize2 = 0;
1703                char input[15360];
1704
1705                hr = IDirectSoundBuffer_Lock ( d->lpDirectSoundOutputBuffer,
1706                        d->writeOffset, msize,
1707                        (void **) &lpOutBuf1, &dwOutSize1,
1708                        (void **) &lpOutBuf2, &dwOutSize2, 0); /* DSBLOCK_FROMWRITECURSOR); */
1709                if (hr != DS_OK)
1710                {
1711                        ms_error("DirectSound IDirectSoundBuffer_Lock failed, hresult = 0x%x\n", hr);
1712                        break;
1713                }
1714
1715                if (dwOutSize1==0)
1716                {
1717                        ms_error("no free room to play sample\n");
1718                }
1719                else if (dwOutSize1+dwOutSize2!=msize)
1720                {
1721                        ms_bufferizer_read(&d->output_buff,(uint8_t*)input,dwOutSize1+dwOutSize2);
1722                        memcpy(lpOutBuf1, input, dwOutSize1);
1723                        memcpy(lpOutBuf2, input+dwOutSize1, dwOutSize2);
1724                }
1725                else if (dwOutSize1>=msize)
1726                {
1727                        ms_bufferizer_read(&d->output_buff,(uint8_t*)input,msize);
1728                        memcpy(lpOutBuf1, input, msize);
1729                }
1730                else
1731                {
1732                        ms_bufferizer_read(&d->output_buff,(uint8_t*)input,msize);
1733                        memcpy(lpOutBuf1, input, dwOutSize1);
1734                        memcpy(lpOutBuf2, input+dwOutSize1, dwOutSize2);
1735                }
1736
1737                d->writeOffset=(d->writeOffset+dwOutSize1+dwOutSize2) % d->framesPerDSBuffer;
1738                msize_max = msize_max - (dwOutSize1+dwOutSize2);
1739                if (msize>msize_max)
1740                        msize = msize_max;
1741                IDirectSoundBuffer_Unlock( d->lpDirectSoundOutputBuffer,
1742                        lpOutBuf1, dwOutSize1, lpOutBuf2, dwOutSize2);
1743                if (dwOutSize1==0)
1744                        break;
1745                if (dwOutSize1+dwOutSize2!=msize)
1746                        break;
1747        }
1748        if (msize==0)
1749        {
1750                if (ms_bufferizer_get_avail(&d->output_buff)>=3*d->wfx.nSamplesPerSec/50)
1751                {
1752                        ms_warning("Removing extra data for sound card %i", ms_bufferizer_get_avail(&d->output_buff));
1753                        ms_bufferizer_uninit(&d->output_buff);
1754                        ms_bufferizer_init(&d->output_buff);
1755                }
1756        }
1757
1758        if (discarded>0)
1759                ms_warning("Extra data for sound card removed (%i buf), (playing: %i) (input-output: %i)", discarded, d->nbufs_playing, d->stat_input - d->stat_output);
1760}
1761
1762static int get_rate(MSFilter *f, void *arg){
1763        WinSndDs *d=(WinSndDs*)f->data;
1764        *((int*)arg)=d->wfx.nSamplesPerSec;
1765        return 0;
1766}
1767
1768static int set_rate(MSFilter *f, void *arg){
1769        WinSndDs *d=(WinSndDs*)f->data;
1770        d->wfx.nSamplesPerSec=*((int*)arg);
1771        return 0;
1772}
1773
1774static int set_nchannels(MSFilter *f, void *arg){
1775        WinSndDs *d=(WinSndDs*)f->data;
1776        d->wfx.nChannels=*((int*)arg);
1777        return 0;
1778}
1779
1780static int winsndds_get_stat_input(MSFilter *f, void *arg){
1781        WinSndDs *d=(WinSndDs*)f->data;
1782        return d->stat_input;
1783}
1784
1785static int winsndds_get_stat_ouptut(MSFilter *f, void *arg){
1786        WinSndDs *d=(WinSndDs*)f->data;
1787
1788        return d->stat_output;
1789}
1790
1791static int winsndds_get_stat_discarded(MSFilter *f, void *arg){
1792        WinSndDs *d=(WinSndDs*)f->data;
1793
1794        return d->stat_notplayed;
1795}
1796
1797static MSFilterMethod winsndds_methods[]={
1798        {       MS_FILTER_GET_SAMPLE_RATE       , get_rate      },
1799        {       MS_FILTER_SET_SAMPLE_RATE       , set_rate      },
1800        {       MS_FILTER_SET_NCHANNELS         , set_nchannels },
1801        {       MS_FILTER_GET_STAT_INPUT, winsndds_get_stat_input },
1802        {       MS_FILTER_GET_STAT_OUTPUT, winsndds_get_stat_ouptut },
1803        {       MS_FILTER_GET_STAT_DISCARDED, winsndds_get_stat_discarded },
1804        {       0                               , NULL          }
1805};
1806
1807MSFilterDesc winsndds_read_desc={
1808        MS_WINSNDDS_READ_ID,
1809        "DirecSoundRead",
1810        "DirectSound capture filter for Windows",
1811        MS_FILTER_OTHER,
1812        NULL,
1813        0,
1814        1,
1815        winsndds_init,
1816        winsndds_read_preprocess,
1817        winsndds_read_process,
1818        winsndds_read_postprocess,
1819        winsndds_uninit,
1820        winsndds_methods
1821};
1822
1823
1824MSFilterDesc winsndds_write_desc={
1825        MS_WINSNDDS_WRITE_ID,
1826        "DirecSoundWrite",
1827        "DirectSound playback filter for Windows",
1828        MS_FILTER_OTHER,
1829        NULL,
1830        1,
1831        0,
1832        winsndds_init,
1833        winsndds_write_preprocess,
1834        winsndds_write_process,
1835        winsndds_write_postprocess,
1836        winsndds_uninit,
1837        winsndds_methods
1838};
1839
1840MSFilter *ms_winsndds_read_new(MSSndCard *card){
1841        MSFilter *f=ms_filter_new_from_desc(&winsndds_read_desc);
1842        WinSndDsCard *wc=(WinSndDsCard*)card->data;
1843        WinSndDs *d=(WinSndDs*)f->data;
1844        d->dev_id=wc->in_devid;
1845        memcpy(&d->in_guid, &wc->in_guid, sizeof(GUID));
1846        memcpy(&d->out_guid, &wc->out_guid, sizeof(GUID));
1847        return f;
1848}
1849
1850
1851MSFilter *ms_winsndds_write_new(MSSndCard *card){
1852        MSFilter *f=ms_filter_new_from_desc(&winsndds_write_desc);
1853        WinSndDsCard *wc=(WinSndDsCard*)card->data;
1854        WinSndDs *d=(WinSndDs*)f->data;
1855        d->dev_id=wc->out_devid;
1856        memcpy(&d->in_guid, &wc->in_guid, sizeof(GUID));
1857        memcpy(&d->out_guid, &wc->out_guid, sizeof(GUID));
1858        return f;
1859}
1860
1861MS_FILTER_DESC_EXPORT(winsndds_read_desc)
1862MS_FILTER_DESC_EXPORT(winsndds_write_desc)
1863
1864#endif
Note: See TracBrowser for help on using the repository browser.