root/rat/trunk/auddev_win32.c @ 2400

Revision 2400, 51.7 KB (checked in by ucacoxh, 15 years ago)

- added make_microphone first port and it does. Bit of a hack, but can't stand
seeing MIDI come up as default port with soundblasters...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2* FILE: auddev_win32.c
3*
4* Written by Orion Hodson and Isidor Kouvelas
5*
6* Some portions based on the VAT Win95 port by John Brezak.
7*
8* $Id$
9*
10* Copyright (c) 1995-99 University College London
11* All rights reserved.
12*
13*/
14
15#ifdef WIN32
16
17#include "config_win32.h"
18#include "audio.h"
19#include "debug.h"
20#include "memory.h"
21#include "auddev_win32.h"
22#include "audio_types.h"
23#include "audio_fmt.h"
24#include "util.h"
25#include "mmsystem.h"
26
27#define rat_to_device(x)        ((x) * 255 / MAX_AMP)
28#define device_to_rat(x)        ((x) * MAX_AMP / 255)
29
30#define W32SDK_MAX_DEVICES 5
31static  int have_probed[W32SDK_MAX_DEVICES];
32static  int w32sdk_probe_formats(audio_desc_t ad);
33
34static int  error = 0;
35static char errorText[MAXERRORLENGTH];
36extern int  thread_pri;
37static int  nLoopGain = 100;
38#define     MAX_DEV_NAME 64
39
40/* mcd_elem_t is a node used to store control state so
41 * we can restore mixer controls when device closes.
42 */
43
44typedef struct s_mcd_elem {
45        MIXERCONTROLDETAILS *pmcd;
46        struct s_mcd_elem   *next;
47} mcd_elem_t;
48
49static mcd_elem_t *control_list;
50
51#define MIX_ERR_LEN 32
52#define MIX_MAX_CTLS 8
53#define MIX_MAX_GAIN 100
54
55static int32    play_vol, rec_vol;
56static HMIXER   hMixer;
57
58static DWORD    dwRecLineID, dwVolLineID;
59
60static audio_port_details_t *input_ports, *loop_ports;
61static int                   n_input_ports, n_loop_ports;
62static int iport; /* Current input port */
63
64/* DEBUGGING FUNCTIONS ******************************************************/
65
66static const char *
67mixGetErrorText(MMRESULT mmr)
68{
69#ifndef NDEBUG
70        switch (mmr) {
71        case MMSYSERR_NOERROR:     return "no error";
72        case MIXERR_INVALLINE:     return "invalid line";
73        case MIXERR_INVALCONTROLreturn "invalid control";
74        case MIXERR_INVALVALUE:    return "invalid value";
75        case WAVERR_BADFORMAT:     return "bad format";
76        case MMSYSERR_BADDEVICEID: return "bad device id";
77        case MMSYSERR_INVALFLAG:   return "invalid flag";
78        case MMSYSERR_INVALHANDLE: return "invalid handle";
79        case MMSYSERR_INVALPARAMreturn "invalid param";
80        case MMSYSERR_NODRIVER:    return "no driver!";
81        }
82        return "Undefined Error";
83#endif /* NDEBUG */
84        return "Mixer Error.";
85}
86
87static const char *
88mixGetControlType(DWORD dwCtlType)
89{
90        switch(dwCtlType) {
91        case MIXERCONTROL_CONTROLTYPE_CUSTOM:        return "Custom";         
92        case MIXERCONTROL_CONTROLTYPE_BOOLEANMETERreturn "Boolean Meter";
93        case MIXERCONTROL_CONTROLTYPE_SIGNEDMETER:   return "Signed Meter";
94        case MIXERCONTROL_CONTROLTYPE_PEAKMETER:     return "PeakMeter";
95        case MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER: return "Unsigned Meter";
96        case MIXERCONTROL_CONTROLTYPE_BOOLEAN:       return "Boolean";
97        case MIXERCONTROL_CONTROLTYPE_ONOFF:         return "OnOff";
98        case MIXERCONTROL_CONTROLTYPE_MUTE:          return "Mute";
99        case MIXERCONTROL_CONTROLTYPE_MONO:          return "Mono";
100        case MIXERCONTROL_CONTROLTYPE_LOUDNESS:      return "Loudness";
101        case MIXERCONTROL_CONTROLTYPE_STEREOENH:     return "Stereo Enhanced";
102        case MIXERCONTROL_CONTROLTYPE_BUTTON:        return "Button";
103        case MIXERCONTROL_CONTROLTYPE_DECIBELS:      return "Decibels";
104        case MIXERCONTROL_CONTROLTYPE_SIGNED:        return "Signed";
105        case MIXERCONTROL_CONTROLTYPE_UNSIGNED:      return "Unsigned";
106        case MIXERCONTROL_CONTROLTYPE_PERCENT:       return "Percent";
107        case MIXERCONTROL_CONTROLTYPE_SLIDER:        return "Slider";
108        case MIXERCONTROL_CONTROLTYPE_PAN:           return "Pan";
109        case MIXERCONTROL_CONTROLTYPE_QSOUNDPAN:     return "Q Sound Pan";
110        case MIXERCONTROL_CONTROLTYPE_FADER:         return "Fader";
111        case MIXERCONTROL_CONTROLTYPE_VOLUME:        return "Volume";
112        case MIXERCONTROL_CONTROLTYPE_BASS:          return "Bass";
113        case MIXERCONTROL_CONTROLTYPE_TREBLE:        return "Treble";
114        case MIXERCONTROL_CONTROLTYPE_EQUALIZER:     return "Equalizer";
115        case MIXERCONTROL_CONTROLTYPE_SINGLESELECTreturn "Single Select";
116        case MIXERCONTROL_CONTROLTYPE_MUX:           return "Mux";
117        case MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT:return "Multiple Select";
118        case MIXERCONTROL_CONTROLTYPE_MIXER:         return "Mixer";
119        case MIXERCONTROL_CONTROLTYPE_MICROTIME:     return "Micro Time";
120        case MIXERCONTROL_CONTROLTYPE_MILLITIME:     return "Milli Time";
121        }
122        return "Unknown";
123}
124
125static void
126mixerDumpLineInfo(HMIXEROBJ hMix, DWORD dwLineID)
127{
128        MIXERLINECONTROLS mlc;
129        LPMIXERCONTROL    pmc;
130        MIXERLINE ml;
131        MMRESULT  mmr;
132        UINT      i;
133       
134        /* Determine number of controls */
135        ml.cbStruct = sizeof(ml);
136        ml.dwLineID = dwLineID;
137       
138        mmr = mixerGetLineInfo((HMIXEROBJ)hMix, &ml, MIXER_GETLINEINFOF_LINEID | MIXER_OBJECTF_HMIXER);
139        if (mmr != MMSYSERR_NOERROR) {
140                debug_msg(mixGetErrorText(mmr));
141                return;
142        }
143       
144        pmc = (LPMIXERCONTROL)xmalloc(sizeof(MIXERCONTROL)*ml.cControls);
145        mlc.cbStruct  = sizeof(MIXERLINECONTROLS);
146        mlc.cbmxctrl  = sizeof(MIXERCONTROL);
147        mlc.pamxctrl  = pmc;
148        mlc.cControls = ml.cControls;
149        mlc.dwLineID  = dwLineID;
150       
151        mmr = mixerGetLineControls((HMIXEROBJ)hMix, &mlc, MIXER_GETLINECONTROLSF_ALL | MIXER_OBJECTF_HMIXER);
152        if (mmr != MMSYSERR_NOERROR) {
153                debug_msg(mixGetErrorText(mmr));
154                xfree(pmc);
155                return;
156        }
157       
158        for(i = 0; i < ml.cControls; i++) {
159                debug_msg("- %u %s\t\t %s\n", i, pmc[i].szName, mixGetControlType(pmc[i].dwControlType));
160        }
161        xfree(pmc);
162}
163
164/* CODE FOR SAVING CONTROL STATES WHEN CLAIMING DEVICE, SO WE CAN RESTORE THE
165 * CONFIG WHEN WE RELEASE THE DEVICE.  CAN BE VERY DISCONCERTING FOR USERS
166 * OTHERWISE *************************/
167
168int
169mcd_elem_add_control(mcd_elem_t **pplist, MIXERCONTROLDETAILS *pmcd)
170{
171        mcd_elem_t *elem;
172       
173        elem = (mcd_elem_t*)xmalloc(sizeof(mcd_elem_t));
174        if (elem) {
175                elem->pmcd = pmcd;
176                elem->next = *pplist;
177                *pplist    = elem;
178                return TRUE;
179        }
180        return FALSE;
181}
182
183MIXERCONTROLDETAILS*
184mcd_elem_get_control(mcd_elem_t **pplist)
185{
186        MIXERCONTROLDETAILS *pmcd;
187        mcd_elem_t *elem;
188       
189        elem = *pplist;
190        if (elem) {
191                pmcd    = elem->pmcd;
192                *pplist = elem->next;
193                xfree(elem);
194                return pmcd;
195        }
196        return NULL;
197}
198
199void
200mixRestoreControls(UINT uMix, mcd_elem_t **pplist)
201{
202        MIXERCONTROLDETAILS *pmcd;
203        MMRESULT mmr;
204       
205        while((pmcd = mcd_elem_get_control(pplist)) != NULL) {
206                mmr = mixerSetControlDetails((HMIXEROBJ)uMix, pmcd, MIXER_OBJECTF_MIXER);
207                xfree(pmcd->paDetails);
208                xfree(pmcd);
209                if (mmr != MMSYSERR_NOERROR) {
210                        debug_msg("mixerSetControlDetails: %s\n", mixGetErrorText(mmr));
211                        continue;
212                }
213        }
214        assert(*pplist == NULL);
215}
216
217void
218mixSaveLine(UINT uMix, MIXERLINE *pml, mcd_elem_t **pplist)
219{
220        MIXERCONTROLDETAILS *pmcd;
221        MIXERLINECONTROLS mlc;
222        MIXERCONTROL     *pmc;
223        MMRESULT          mmr;
224        UINT              i;
225       
226        /* Retrieve control types */
227        pmc = (MIXERCONTROL*)xmalloc(sizeof(MIXERCONTROL)*pml->cControls);
228       
229        mlc.cbStruct  = sizeof(mlc);
230        mlc.dwLineID  = pml->dwLineID;
231        mlc.cControls = pml->cControls;
232        mlc.pamxctrl  = pmc;
233        mlc.cbmxctrl  = sizeof(MIXERCONTROL);
234       
235        debug_msg("Saving %s\n", pml->szName);
236
237        mmr = mixerGetLineControls((HMIXEROBJ)uMix, &mlc, MIXER_GETLINECONTROLSF_ALL | MIXER_OBJECTF_MIXER);
238        if (mmr != MMSYSERR_NOERROR) {
239                debug_msg("mixerGetLineControls: %s\n", mixGetErrorText(mmr));
240                xfree(pmc);
241                return;
242        }
243       
244        for(i = 0; i < pml->cControls; i++) {
245                DWORD itemCnt, itemSz;
246                if (pmc[i].cMultipleItems == 0) {
247                        itemCnt = 1;   
248                } else {
249                        itemCnt = pmc[i].cMultipleItems;
250                }
251               
252                switch(pmc[i].dwControlType & MIXERCONTROL_CT_UNITS_MASK) {
253                        /* Our application on affects boolean types (mute, on/off) and unsigned (vol) */
254                case MIXERCONTROL_CT_UNITS_BOOLEAN:
255                        itemSz = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
256                        break;
257                case MIXERCONTROL_CT_UNITS_UNSIGNED:
258                        itemSz = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
259                        break;
260                default:
261                        debug_msg("not done %s\n", pmc[i].szName);
262                        continue;
263                }
264                pmcd = (MIXERCONTROLDETAILS*)xmalloc(sizeof(MIXERCONTROLDETAILS));
265                pmcd->cbStruct       = sizeof(MIXERCONTROLDETAILS);
266                pmcd->cMultipleItems = pmc[i].cMultipleItems;
267                pmcd->dwControlID    = pmc[i].dwControlID;
268                pmcd->cChannels      = 1;
269                pmcd->paDetails      = (void*)xmalloc(itemSz * itemCnt);
270                pmcd->cbDetails      = itemSz;
271               
272                mmr = mixerGetControlDetails((HMIXEROBJ)uMix, pmcd, MIXER_GETCONTROLDETAILSF_VALUE | MIXER_OBJECTF_MIXER);
273                if (mmr != MMSYSERR_NOERROR) {
274                        debug_msg("mixerGetControlDetails: %s\n", mixGetErrorText(mmr));
275                        continue;
276                }
277                mcd_elem_add_control(pplist, pmcd);
278        }
279        xfree(pmc);
280}
281
282
283void
284mixSaveControls(UINT uMix, mcd_elem_t **pplist)
285{
286        MIXERLINE ml, sml;
287        MIXERCAPS mc;
288        MMRESULT  mmr;
289        UINT i,j;
290       
291        mmr = mixerGetDevCaps(uMix, &mc, sizeof(mc));
292        if (mmr != MMSYSERR_NOERROR) {
293                debug_msg("mixerGetDevCaps: %s\n", mixGetErrorText(mmr));
294                return;
295        }
296       
297        for(i = 0; i < mc.cDestinations; i++) {
298                memset(&ml, 0, sizeof(ml));
299                ml.cbStruct      = sizeof(ml);
300                ml.dwDestination = i;
301                mmr = mixerGetLineInfo((HMIXEROBJ)uMix, &ml, MIXER_OBJECTF_MIXER | MIXER_GETLINEINFOF_DESTINATION);
302                if (mmr != MMSYSERR_NOERROR) {
303                        debug_msg("mixerGetLineInfo: %s\n", mixGetErrorText(mmr));
304                        continue;
305                }
306                mixSaveLine(uMix, &ml, pplist);
307                for (j = 0; j < ml.cConnections; j++) {
308                        memset(&sml, 0, sizeof(sml));
309                        sml.cbStruct = sizeof(sml);
310                        sml.dwSource = j;
311                        mmr = mixerGetLineInfo((HMIXEROBJ)uMix, &sml, MIXER_OBJECTF_MIXER | MIXER_GETLINEINFOF_SOURCE);
312                        if (mmr != MMSYSERR_NOERROR) {
313                                debug_msg("mixerGetLineInfo: %s\n", mixGetErrorText(mmr));
314                                continue;
315                        }
316                        mixSaveLine(uMix, &sml, pplist);
317                }
318        }
319}
320
321/* CODE FOR CONTROLLING INPUT AND OUTPUT (LOOPBACK) LINES *******************
322 * NOTE: the control of input lines and output lines is slightly different
323 * because most card manufacturers put the volume and mute controls for output
324 * as controls on the same output line.  The selection of the input lines is
325 * controlled on the MUX control actually on the recording source, and the
326 * volume control is on a line for the the input port.  To match the input
327 * select and the volume control we use the name of the line the volume
328 * control is assigned to, and this ties in with the names on the MUX.  This
329 * seems to be the only sensible way to correlate the two and IT ISN'T IN
330 * THE MSDN LIBRARY documentation.  I wasted a fair amount of time, trying
331 * to match the name of the volume control and names in the MUX list, and
332 * got this to work for all but one card.
333 */
334
335/* mixGetInputInfo - attempt to find corresponding wavein index
336* for mixer uMix and corresponding destination line of mixer. 
337* Returns TRUE if successful.
338*/
339
340int mixGetInputInfo(UINT uMix, UINT *puWavIn, DWORD *pdwLineID)
341{
342        UINT i, nWavIn;
343        MIXERLINE  ml;
344        MMRESULT   mmr;
345        WAVEINCAPS wic;
346        MIXERCAPS  mc;
347       
348        mmr = mixerGetDevCaps(uMix, &mc, sizeof(mc));
349        if (mmr != MMSYSERR_NOERROR) {
350                debug_msg("mixerGetDevCaps: %s\n", mixGetErrorText(mmr));
351                return FALSE;
352        }
353       
354        nWavIn = waveInGetNumDevs();
355        for(i = 0; i < nWavIn; i++) {
356                mmr = waveInGetDevCaps(i, &wic, sizeof(wic));
357                if (mmr != MMSYSERR_NOERROR) {
358                        debug_msg("waveInGetDevCaps: %s\n", mixGetErrorText(mmr));
359                        continue;
360                }
361               
362                ml.cbStruct       = sizeof(ml);
363                ml.Target.dwType  = MIXERLINE_TARGETTYPE_WAVEIN;
364                strncpy(ml.Target.szPname, wic.szPname, MAXPNAMELEN);
365                ml.Target.vDriverVersion = wic.vDriverVersion;
366                ml.Target.wMid    = wic.wMid;
367                ml.Target.wPid    = wic.wPid;
368               
369                mmr = mixerGetLineInfo((HMIXEROBJ)uMix, &ml, MIXER_OBJECTF_MIXER | MIXER_GETLINEINFOF_TARGETTYPE);
370                if (mmr == MMSYSERR_NOERROR) {
371                        *puWavIn          = i;
372                        *pdwLineID = ml.dwLineID;
373                        debug_msg("Input: %s(%d - %d)\n", ml.szName, ml.dwDestination, ml.dwLineID);
374                        return TRUE;
375                } else {
376                        debug_msg("mixerGetLineInfo (ignore this error): %s\n", mixGetErrorText(mmr));
377                }
378        }
379        return FALSE;
380}
381
382/* mixGetOutputInfo - attempt to find corresponding waveout index
383 * and corresponding destination line of mixer.  Returns TRUE if
384 * successful.
385 */
386int 
387mixGetOutputInfo(UINT uMix, UINT *puWavOut, DWORD *pdwLineID)
388{
389        UINT i, nWavOut;
390        MIXERLINE  ml;
391        MMRESULT   mmr;
392        WAVEOUTCAPS woc;
393        MIXERCAPS  mc;
394       
395        mmr = mixerGetDevCaps(uMix, &mc, sizeof(mc));
396        if (mmr != MMSYSERR_NOERROR) {
397                debug_msg("mixerGetDevCaps: %s\n", mixGetErrorText(mmr));
398                return FALSE;
399        }
400       
401        nWavOut = waveOutGetNumDevs();
402        for(i = 0; i < nWavOut; i++) {
403                mmr = waveOutGetDevCaps(i, &woc, sizeof(woc));
404                if (mmr != MMSYSERR_NOERROR) {
405                        debug_msg("waveOutGetDevCaps: %s\n", mixGetErrorText(mmr));
406                        continue;
407                }
408                ml.cbStruct       = sizeof(ml);
409                ml.Target.dwType  = MIXERLINE_TARGETTYPE_WAVEOUT;
410                strncpy(ml.Target.szPname, woc.szPname, MAXPNAMELEN);
411                ml.Target.vDriverVersion = woc.vDriverVersion;
412                ml.Target.wMid    = woc.wMid;
413                ml.Target.wPid    = woc.wPid;
414               
415                mmr = mixerGetLineInfo((HMIXEROBJ)uMix, &ml, MIXER_OBJECTF_MIXER | MIXER_GETLINEINFOF_TARGETTYPE);
416                if (mmr == MMSYSERR_NOERROR) {
417                        *puWavOut  = i;
418                        *pdwLineID = ml.dwLineID;
419                        debug_msg("Output: %s(%d - %d)\n", ml.szName, ml.dwDestination, ml.dwLineID);
420                        return TRUE;
421                }
422        }
423        return FALSE;
424}
425
426/* mixerEnableInputLine - enables the input line whose name starts with beginning of portname. 
427 * We cannot just use the port index like we do for volume because the mute controls are
428 * not necessarily in the same order as the volume controls (grrr!).  The only card
429 * that we have seen where this is necessary is the Winnov Videum AV, but there are
430 * bound to be others.
431 * Muting for input lines on the toplevel control (Rec, or whatever driver happens to call it).
432 * It usually has a single control a MUX/Mixer that has "multiple items", one mute for
433 * each input line.  Depending on the control type it may be legal to have multiple input
434 * lines enabled, or just one.  So mixerEnableInputLine disables all lines other than
435 * one selected.
436 */
437
438static int
439mixerEnableInputLine(HMIXEROBJ hMix, char *portname)
440{
441        MIXERCONTROLDETAILS_BOOLEAN *mcdbState;
442        MIXERCONTROLDETAILS_LISTTEXT *mcdlText;
443        MIXERCONTROLDETAILS mcd;
444        MIXERLINECONTROLS mlc;
445        MIXERCONTROL mc;
446        MIXERLINE ml;
447        MMRESULT  mmr;
448        UINT      i, matchLine;
449       
450        ml.cbStruct = sizeof(ml);
451        ml.dwLineID = dwRecLineID;
452       
453        mmr = mixerGetLineInfo(hMix, &ml, MIXER_GETLINEINFOF_LINEID|MIXER_OBJECTF_HMIXER);
454        if (mmr != MMSYSERR_NOERROR) {
455                debug_msg("mixerGetLineInfo: %s\n", mixGetErrorText(mmr));
456        }
457       
458        /* Get Mixer/MUX control information (need control id to set and get control details) */
459        mlc.cbStruct      = sizeof(mlc);
460        mlc.dwLineID      = ml.dwLineID;
461        mlc.pamxctrl      = &mc;
462        mlc.cbmxctrl      = sizeof(mc);
463       
464        mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MUX; /* Single Select */
465        mmr = mixerGetLineControls(hMix, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE|MIXER_OBJECTF_HMIXER);
466        if (mmr != MMSYSERR_NOERROR) {
467                mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MIXER; /* Multiple Select */
468                mmr = mixerGetLineControls(hMix, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE|MIXER_OBJECTF_HMIXER);
469                if (mmr != MMSYSERR_NOERROR) {
470                        debug_msg("mixerGetLineControls: %s\n", mixGetErrorText(mmr));
471                        return FALSE;
472                }
473        }
474       
475        mcd.cbStruct    = sizeof(mcd);
476        mcd.dwControlID = mc.dwControlID;
477        mcd.cChannels   = 1;
478        mcd.cMultipleItems = mc.cMultipleItems;
479        mcdlText = (MIXERCONTROLDETAILS_LISTTEXT*)xmalloc(sizeof(MIXERCONTROLDETAILS_LISTTEXT)*mc.cMultipleItems);       
480        mcd.paDetails = mcdlText;
481        mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXT);
482        mmr = mixerGetControlDetails(hMix, &mcd, MIXER_GETCONTROLDETAILSF_LISTTEXT | MIXER_OBJECTF_MIXER);
483       
484        matchLine = 0;
485        for(i = 0; i < mcd.cMultipleItems; i++) {
486                if (!strcmp(mcdlText[i].szName, portname)) {
487                        matchLine = i;
488                        break;
489                }
490        }
491        xfree(mcdlText);
492
493        /* Now get control itself */
494        mcd.cbStruct    = sizeof(mcd);
495        mcd.dwControlID = mc.dwControlID;
496        mcd.cChannels   = 1;
497        mcd.cMultipleItems = mc.cMultipleItems;
498        mcdbState = (MIXERCONTROLDETAILS_BOOLEAN*)xmalloc(sizeof(MIXERCONTROLDETAILS_BOOLEAN)*mc.cMultipleItems);       
499        mcd.paDetails = mcdbState;
500        mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
501       
502        mmr = mixerGetControlDetails(hMix, &mcd, MIXER_GETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_MIXER);
503        if (mmr != MMSYSERR_NOERROR) {
504                debug_msg("mixerGetControlDetails: %s\n", mixGetErrorText(mmr));
505                xfree(mcdbState);
506                return FALSE;
507        }
508       
509        for(i = 0; i < mcd.cMultipleItems; i++) {
510                if (i == matchLine) {
511                        mcdbState[i].fValue = TRUE;
512                } else {
513                        mcdbState[i].fValue = FALSE;
514                }
515        }
516       
517        mmr = mixerSetControlDetails(hMix, &mcd, MIXER_OBJECTF_MIXER);
518        if (mmr != MMSYSERR_NOERROR) {
519                debug_msg("mixerSetControlDetails: %s\n", mixGetErrorText(mmr));
520                xfree(mcdbState);
521                return FALSE;
522        }
523       
524        xfree(mcdbState);
525        return TRUE;
526}
527
528static int
529mixerEnableOutputLine(HMIXEROBJ hMix, DWORD dwLineID, int state)
530{
531        MIXERCONTROLDETAILS_BOOLEAN mcdbState;
532        MIXERCONTROLDETAILS mcd;
533        MIXERLINECONTROLS mlc;
534        MIXERCONTROL      mc;
535        MMRESULT          mmr;
536       
537        mlc.cbStruct      = sizeof(mlc);
538        mlc.pamxctrl      = &mc;
539        mlc.cbmxctrl      = sizeof(MIXERCONTROL);
540        mlc.dwLineID      = dwLineID;
541        mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE;
542       
543        mmr = mixerGetLineControls(hMix, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE | MIXER_OBJECTF_HMIXER);
544        if (mmr != MMSYSERR_NOERROR) {
545                mlc.cbStruct      = sizeof(mlc);
546                mlc.pamxctrl      = &mc;
547                mlc.cbmxctrl      = sizeof(MIXERCONTROL);
548                mlc.dwLineID      = dwLineID;
549                mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_ONOFF;
550                mmr = mixerGetLineControls(hMix, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE | MIXER_OBJECTF_HMIXER);
551                if (mmr != MMSYSERR_NOERROR) {
552                        debug_msg("Could not get mute control for line 0x%08x: %s\n",
553                                dwLineID,
554                                mixGetErrorText(mmr));
555                        mixerDumpLineInfo(hMix, dwLineID);
556                        return FALSE;
557                }
558        }
559       
560        mcd.cbStruct       = sizeof(mcd);
561        mcd.dwControlID    = mc.dwControlID;
562        mcd.cChannels      = 1;
563        mcd.cMultipleItems = mc.cMultipleItems;
564        mcd.cbDetails      = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
565        mcd.paDetails      = &mcdbState;
566        mcdbState.fValue   = !((UINT)state);
567       
568        mmr = mixerSetControlDetails((HMIXEROBJ)hMix, &mcd, MIXER_OBJECTF_HMIXER);
569        if (mmr != MMSYSERR_NOERROR) {
570                debug_msg("Could not set mute state for line 0x%08x\n", dwLineID);
571                return FALSE;
572        }
573        return TRUE;
574}
575
576/* MixerSetLineGain - sets gain of line (range 0-MIX_MAX_GAIN) */
577static int
578mixerSetLineGain(HMIXEROBJ hMix, DWORD dwLineID, int gain)
579{
580        MIXERCONTROLDETAILS_UNSIGNED mcduGain;
581        MIXERCONTROLDETAILS mcd;
582        MIXERLINECONTROLS mlc;
583        MIXERCONTROL      mc;
584        MMRESULT          mmr;
585       
586        mlc.cbStruct      = sizeof(mlc);
587        mlc.pamxctrl      = &mc;
588        mlc.cbmxctrl      = sizeof(MIXERCONTROL);
589        mlc.dwLineID      = dwLineID;
590        mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
591       
592        mmr = mixerGetLineControls(hMix, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE | MIXER_OBJECTF_HMIXER);
593        if (mmr != MMSYSERR_NOERROR) {
594                debug_msg("Could not volume control for line 0x%08x: %s\n",
595                        dwLineID,
596                        mixGetErrorText(mmr));
597                return FALSE;       
598        }
599       
600        mcd.cbStruct       = sizeof(mcd);
601        mcd.dwControlID    = mc.dwControlID;
602        mcd.cChannels      = 1;
603        mcd.cMultipleItems = mc.cMultipleItems;
604        mcd.cbDetails      = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
605        mcd.paDetails      = &mcduGain;
606        mcduGain.dwValue   = ((mc.Bounds.dwMaximum - mc.Bounds.dwMinimum) * gain)/MIX_MAX_GAIN;
607       
608        mmr = mixerSetControlDetails((HMIXEROBJ)hMix, &mcd, MIXER_OBJECTF_HMIXER);
609        if (mmr != MMSYSERR_NOERROR) {
610                debug_msg("Could not set gain for line 0x%08x: %s\n", dwLineID, mixGetErrorText(mmr));
611                return FALSE;
612        }
613        return TRUE;
614}
615
616/* MixerGetLineGain - returns gain of line (range 0-MIX_MAX_GAIN) */
617static int
618mixerGetLineGain(HMIXEROBJ hMix, DWORD dwLineID)
619{
620        MIXERCONTROLDETAILS_UNSIGNED mcduGain;
621        MIXERCONTROLDETAILS mcd;
622        MIXERLINECONTROLS mlc;
623        MIXERCONTROL      mc;
624        MMRESULT          mmr;
625       
626        mlc.cbStruct      = sizeof(mlc);
627        mlc.pamxctrl      = &mc;
628        mlc.cbmxctrl      = sizeof(MIXERCONTROL);
629        mlc.dwLineID      = dwLineID;
630        mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
631       
632        mmr = mixerGetLineControls(hMix, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE | MIXER_OBJECTF_HMIXER);
633        if (mmr != MMSYSERR_NOERROR) {
634                debug_msg("Could not find volume control for line 0x%08x\n", dwLineID);
635                return 0;       
636        }
637       
638        mcd.cbStruct       = sizeof(mcd);
639        mcd.dwControlID    = mc.dwControlID;
640        mcd.cChannels      = 1;
641        mcd.cMultipleItems = mc.cMultipleItems;
642        mcd.cbDetails      = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
643        mcd.paDetails      = &mcduGain;
644       
645        mmr = mixerGetControlDetails((HMIXEROBJ)hMix, &mcd, MIXER_OBJECTF_HMIXER);
646        if (mmr != MMSYSERR_NOERROR) {
647                debug_msg("Could not get gain for line 0x%08x\n", dwLineID);
648                return 0;
649        }
650        return (int)(mcduGain.dwValue * MIX_MAX_GAIN / (mc.Bounds.dwMaximum - mc.Bounds.dwMinimum));
651}
652
653static int
654mixerGetLineName(HMIXEROBJ hMix, DWORD dwLineID, char *szName, UINT uLen)
655{
656        MIXERLINE           ml;
657        MIXERLINECONTROLS   mlc;
658        MIXERCONTROL        mc;
659        MMRESULT            mmr;
660       
661        mlc.cbStruct      = sizeof(mlc);
662        mlc.pamxctrl      = &mc;
663        mlc.cbmxctrl      = sizeof(MIXERCONTROL);
664        mlc.dwLineID      = dwLineID;
665        mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
666/*       
667        mmr = mixerGetLineControls(hMix, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE | MIXER_OBJECTF_HMIXER);
668        if (mmr != MMSYSERR_NOERROR) {
669                debug_msg("Could not find volume control for line 0x%08x: %s\n", dwLineID, mixGetErrorText(mmr));
670                return FALSE;       
671        }
672*/
673        memset(&ml,0, sizeof(MIXERLINE));
674        ml.cbStruct = sizeof(MIXERLINE);
675        ml.dwLineID = dwLineID;
676        mmr = mixerGetLineInfo(hMix, &ml, MIXER_GETLINEINFOF_LINEID);
677        if (mmr != MMSYSERR_NOERROR) {
678                debug_msg("poo");
679        }
680        debug_msg("line name %s\n", ml.szName);
681        strncpy(szName, ml.szName, uLen);
682        return TRUE;
683}
684
685/* MixQueryControls: Get all line names and id's, fill into ppapd, and return number of lines */
686static int
687mixQueryControls(HMIXEROBJ hMix, DWORD dwLineID, audio_port_details_t** ppapd)
688{
689        MIXERCAPS mc;
690        MIXERLINE mlt, mlc;
691        audio_port_details_t *papd;
692        MMRESULT mmr;
693        UINT     i;
694       
695        /* Videum bug work around - Videum does not fill in number of connections if
696         * called using MIXER_GETLINEINFOF_LINEID.  This is the only driver with this problem,
697         * but this seems to work in all cases.
698         */       
699        mixerGetDevCaps((UINT)hMix, &mc, sizeof(mc));
700        for(i = 0; i < mc.cDestinations; i++) {
701                memset(&mlt, 0, sizeof(mlt));
702                mlt.cbStruct = sizeof(mlt);
703                mlt.dwDestination = i;
704                mmr = mixerGetLineInfo(hMix, &mlt, MIXER_GETLINEINFOF_DESTINATION);
705                if (mmr != MMSYSERR_NOERROR) {
706                        debug_msg("mixerGetLineInfo: %s\n", mixGetErrorText(mmr));
707                        continue;
708                }
709                if (mlt.dwLineID == dwLineID) {
710                        break;
711                }
712        }
713       
714        papd = (audio_port_details_t*)xmalloc(sizeof(audio_port_details_t)*mlt.cConnections);
715        if (papd == NULL) {
716                return 0;
717        }
718       
719        mixerDumpLineInfo((HMIXEROBJ)hMix, mlt.dwLineID);
720       
721        for(i = 0; i < mlt.cConnections; i++) {
722                memcpy(&mlc, &mlt, sizeof(mlc));
723                mlc.dwSource = i;
724                mmr = mixerGetLineInfo((HMIXEROBJ)hMixer, &mlc, MIXER_GETLINEINFOF_SOURCE|MIXER_OBJECTF_HMIXER);
725                if (mmr != MMSYSERR_NOERROR) {
726                        xfree(papd);
727                        return 0;
728                }
729                strncpy(papd[i].name, mlc.szName, AUDIO_PORT_NAME_LENGTH);
730                papd[i].port = mlc.dwLineID;
731        }
732       
733        *ppapd = papd;
734        return (int)mlt.cConnections;
735}
736
737/* XXX make_microphone_first_port is a hack to make microphone
738 * the first (default) port.  Of course this only works for
739 * english language drivers...
740 */
741
742static int
743make_microphone_first_port(audio_port_details_t *ports, int n_ports)
744{
745        audio_port_details_t tmp;
746        int i;
747       
748        for(i = 1; i < n_ports; i++) {
749                if (!strncasecmp("mic", ports[i].name, 3)) {
750                        memcpy(&tmp, ports + i, sizeof(tmp));
751                        memcpy(ports + i , ports, sizeof(ports[0]));
752                        memcpy(ports, &tmp, sizeof(ports[0]));
753                        return TRUE;
754                }
755        }
756
757        return FALSE;
758}
759
760static int 
761mixSetup(UINT uMixer)
762{
763        MIXERCAPS mc;
764        MMRESULT  res;
765       
766        if (hMixer)  {mixerClose(hMixer);  hMixer  = 0;}
767       
768        res = mixerOpen(&hMixer, uMixer, (unsigned long)NULL, (unsigned long)NULL, MIXER_OBJECTF_MIXER);
769        if (res != MMSYSERR_NOERROR) {
770                debug_msg("mixerOpen failed: %s\n", mixGetErrorText(res));
771                return FALSE;
772        }
773       
774        res = mixerGetDevCaps((UINT)hMixer, &mc, sizeof(mc));
775        if (res != MMSYSERR_NOERROR) {
776                debug_msg("mixerGetDevCaps failed: %s\n", mixGetErrorText(res));
777                return FALSE;
778        }
779       
780        if (mc.cDestinations < 2) {
781                debug_msg("mixer does not have 2 destinations?\n");
782                return FALSE;
783        }
784       
785        if (input_ports != NULL) {
786                xfree(input_ports);
787                input_ports   = NULL;
788                n_input_ports = 0;
789        }
790       
791        n_input_ports = mixQueryControls((HMIXEROBJ)hMixer, dwRecLineID, &input_ports);
792        debug_msg("Input ports %d\n", n_input_ports);
793        if (n_input_ports == 0) {
794                return FALSE;
795        }
796       
797        make_microphone_first_port(input_ports, n_input_ports);
798
799        if (loop_ports != NULL) {
800                xfree(loop_ports);
801                loop_ports   = NULL;
802                n_loop_ports = 0;
803        }
804       
805        n_loop_ports = mixQueryControls((HMIXEROBJ)hMixer, dwVolLineID, &loop_ports);
806        debug_msg("Loop ports %d\n", n_loop_ports);
807        if (n_loop_ports == 0) {
808                return 0;
809        }
810        return TRUE;
811}
812
813static int blksz;
814static int nblks;
815static int smplsz;
816/* AUDIO OUTPUT RELATED FN's ********************************/
817
818static WAVEHDR *write_hdrs, *write_curr, *write_tail;
819static u_char  *write_mem;
820static int      write_hdrs_used;
821static HWAVEOUT shWaveOut;
822
823static int
824w32sdk_audio_open_out(UINT uId, WAVEFORMATEX *pwfx)
825{
826        int             i;
827        WAVEHDR         *whp;
828        u_char          *bp;
829       
830        if (shWaveOut)
831                return (TRUE);
832       
833        error = waveOutOpen(&shWaveOut, uId, pwfx, 0, 0, CALLBACK_NULL);
834        if (error) {
835#ifdef DEBUG
836                waveOutGetErrorText(error, errorText, sizeof(errorText));
837                debug_msg("waveOutOpen: (%d) %s\n", error, errorText);
838#endif
839                return (FALSE);
840        }
841       
842        if (write_mem != NULL) xfree(write_mem);
843        write_mem = (u_char*)xmalloc(nblks * blksz);
844        memset(write_mem, 0, nblks * blksz);
845        if (write_hdrs != NULL) xfree(write_hdrs);
846        write_hdrs = (WAVEHDR*)xmalloc(sizeof(WAVEHDR)*nblks);
847        memset(write_hdrs, 0, sizeof(WAVEHDR)*nblks);
848        for (i = 0, whp = write_hdrs, bp = write_mem; i < nblks; i++, whp++, bp += blksz) {
849                whp->dwFlags        = 0;
850                whp->dwBufferLength = blksz;
851                whp->lpData         = (char*)bp;
852                error = waveOutPrepareHeader(shWaveOut, whp, sizeof(WAVEHDR));
853                if (error) {
854                        waveOutGetErrorText(error, errorText, sizeof(errorText));
855                        debug_msg("Win32Audio: waveOutPrepareHeader: %s\n", errorText);
856                        exit(1);
857                }
858        }
859        write_tail      = write_curr = write_hdrs;
860        write_hdrs_used = 0;
861        return (TRUE);
862}
863
864static void
865w32sdk_audio_close_out()
866{
867        int     i;
868        WAVEHDR         *whp;
869       
870        if (shWaveOut == 0)
871                return;
872       
873        waveOutReset(shWaveOut);
874       
875        for (i = 0, whp = write_hdrs; i < nblks; i++, whp++)
876                if (whp->dwFlags & WHDR_PREPARED)
877                        waveOutUnprepareHeader(shWaveOut, whp, sizeof(WAVEHDR));
878               
879                (void) waveOutClose(shWaveOut);
880                xfree(write_hdrs); write_hdrs = NULL;
881                xfree(write_mem);  write_mem  = NULL;
882                xmemchk();
883                shWaveOut = 0;
884}
885
886#define WRITE_ERROR_STILL_PLAYING 33
887
888int
889w32sdk_audio_write(audio_desc_t ad, u_char *buf , int buf_bytes)
890{
891        int             error, len, done;
892       
893        UNUSED(ad);
894       
895        assert(shWaveOut != 0);
896       
897        while (write_tail->dwFlags & WHDR_DONE) {
898                write_tail->dwFlags &= ~WHDR_DONE;
899                write_hdrs_used--;
900                write_tail++;
901                if (write_tail >= write_hdrs + nblks)
902                        write_tail = write_hdrs;
903        }
904       
905        if (write_hdrs_used > 4*nblks/5) {
906                debug_msg("Running out of write buffers %d left\n", write_hdrs_used);
907        }
908       
909        done = 0;
910        while (buf_bytes > 0) {
911                if (write_curr->dwFlags & WHDR_DONE) {
912                        /* Have overdone it! */
913                        debug_msg("w32sdk_audio_write, reached end of buffer (%06d bytes remain)\n", buf_bytes);
914                        return (done);
915                }
916               
917                len = (buf_bytes > blksz) ? blksz: buf_bytes;
918               
919                memcpy(write_curr->lpData, buf, len);
920                buf += len;
921               
922                error = waveOutWrite(shWaveOut, write_curr, sizeof(WAVEHDR));
923               
924                if (error == WRITE_ERROR_STILL_PLAYING) { /* We've filled device buffer ? */
925                        debug_msg("Win32Audio - device filled. Discarding %d bytes.\n",
926                                buf_bytes);
927                                /* we return as if we wrote everything out
928                                * to give buffer a little breathing room
929                        */
930                        return done;
931                } else if (error) {
932                        waveOutGetErrorText(error, errorText, sizeof(errorText));
933                        debug_msg("Win32Audio: waveOutWrite (%d): %s\n", error, errorText);
934                        return (buf_bytes);
935                }
936               
937                write_curr++;
938                write_hdrs_used++;
939                if (write_curr >= write_hdrs + nblks) {
940                        write_curr = write_hdrs;
941                }
942               
943                done      += blksz;
944                buf_bytes -= blksz;
945        }
946        return (done);
947}
948
949/* AUDIO INPUT RELATED FN's *********************************/
950
951static unsigned char audio_ready = 0;
952
953int
954w32sdk_audio_is_ready(audio_desc_t ad)
955{
956        UNUSED(ad);
957        if (audio_ready>nblks/5) {
958                debug_msg("Lots of audio available (%d blocks)\n", audio_ready);
959        }
960       
961        return (audio_ready>0) ? TRUE : FALSE;
962}
963
964static void CALLBACK
965waveInProc(HWAVEIN hwi,
966           UINT    uMsg,
967           DWORD   dwInstance,
968           DWORD   dwParam1,
969           DWORD   dwParam2)
970{
971        UNUSED(dwInstance);
972        UNUSED(dwParam1);
973        UNUSED(dwParam2);
974        UNUSED(hwi);
975       
976        switch(uMsg) {
977        case WIM_DATA:
978                audio_ready++;
979                break;
980        default:
981                ;  /* nothing to do currently */
982        }
983       
984        return;
985}
986
987static WAVEHDR  *read_hdrs, *read_curr;
988static u_char   *read_mem;
989static HWAVEIN  shWaveIn;
990
991static int
992w32sdk_audio_open_in(UINT uId, WAVEFORMATEX *pwfx)
993{
994        WAVEHDR *whp;
995        int          l;
996        u_char  *bp;
997       
998        if (shWaveIn) return (TRUE);
999       
1000        if (read_mem != NULL) xfree(read_mem);
1001        read_mem = (u_char*)xmalloc(nblks * blksz);
1002       
1003        if (read_hdrs != NULL) xfree(read_hdrs);
1004        read_hdrs = (WAVEHDR*)xmalloc(sizeof(WAVEHDR)*nblks);
1005       
1006        error = waveInOpen(&shWaveIn,
1007                uId,
1008                pwfx,
1009                (unsigned long)waveInProc,
1010                0,
1011                CALLBACK_FUNCTION);
1012        if (error != MMSYSERR_NOERROR) {
1013                waveInGetErrorText(error, errorText, sizeof(errorText));
1014                debug_msg("waveInOpen: (%d) %s\n", error, errorText);
1015                return (FALSE);
1016        }
1017       
1018        /* Provide buffers for reading */
1019        audio_ready = 0;
1020        for (l = 0, whp = read_hdrs, bp = read_mem; l < nblks; l++, whp++, bp += blksz) {
1021                whp->lpData = (char*)bp;
1022                whp->dwBufferLength = blksz;
1023                whp->dwFlags = 0;
1024                error = waveInPrepareHeader(shWaveIn, whp, sizeof(WAVEHDR));
1025                if (error) {
1026                        waveInGetErrorText(error, errorText, sizeof(errorText));
1027                        debug_msg("waveInPrepareHeader: (%d) %s\n", error, errorText);
1028                        exit(1);
1029                }
1030                error = waveInAddBuffer(shWaveIn, whp, sizeof(WAVEHDR));
1031                if (error) {
1032                        waveInGetErrorText(error, errorText, sizeof(errorText));
1033                        debug_msg("waveInAddBuffer: (%d) %s\n", error, errorText);
1034                        exit(1);
1035                }
1036        }
1037        read_curr = read_hdrs;
1038       
1039        error = waveInStart(shWaveIn);
1040        if (error) {
1041                waveInGetErrorText(error, errorText, sizeof(errorText));
1042                debug_msg("Win32Audio: waveInStart: (%d) %s\n", error, errorText);
1043                exit(1);
1044        }
1045       
1046        return (TRUE);
1047}
1048
1049static void
1050w32sdk_audio_close_in()
1051{
1052        int             i;
1053        WAVEHDR         *whp;
1054       
1055        if (shWaveIn == 0)
1056                return;
1057       
1058        waveInStop(shWaveIn);
1059        waveInReset(shWaveIn);
1060       
1061        for (i = 0, whp = read_hdrs; i < nblks; i++, whp++)
1062                if (whp->dwFlags & WHDR_PREPARED)
1063                        waveInUnprepareHeader(shWaveIn, whp, sizeof(WAVEHDR));
1064               
1065                waveInClose(shWaveIn);
1066                shWaveIn = 0;
1067                xfree(read_hdrs); read_hdrs = NULL;
1068                xfree(read_mem);  read_mem  = NULL;
1069                xmemchk();
1070}
1071
1072int
1073w32sdk_audio_read(audio_desc_t ad, u_char *buf, int buf_bytes)
1074{
1075        static int virgin = 0;
1076        int len = 0;
1077       
1078        UNUSED(ad);
1079       
1080        if (!virgin) {
1081                debug_msg("ready %d\n", audio_ready);
1082                virgin++;
1083        }
1084       
1085        assert(buf_bytes >= blksz);
1086        buf_bytes -= buf_bytes % blksz;
1087       
1088        if (audio_ready) {
1089                while ((read_curr->dwFlags & WHDR_DONE) && len < buf_bytes) {
1090                        memcpy(buf, read_curr->lpData, blksz);
1091                        buf += blksz;
1092                        len += blksz;
1093                        read_curr->dwFlags &= ~WHDR_DONE;
1094                        error = waveInAddBuffer(shWaveIn, read_curr, sizeof(WAVEHDR));
1095                        if (error) {
1096                                waveInGetErrorText(error, errorText, sizeof(errorText));
1097                                debug_msg("waveInAddBuffer: (%d) %s\n", error, errorText);
1098                                exit(1);
1099                        }
1100                        read_curr++;
1101                        if (read_curr == read_hdrs + nblks) read_curr = read_hdrs;
1102                        if (audio_ready > 0) audio_ready--;
1103                }
1104#ifdef DEBUG
1105                if (audio_ready > 3*nblks/4) {
1106                        int i,used;
1107                        for(i=0,used=0;i<nblks;i++)
1108                                if (read_hdrs[i].dwFlags & WHDR_DONE) used++;
1109                                debug_msg("RB small %d of %d len %d, ready %d\n", used, nblks, len, audio_ready);
1110                }
1111#endif
1112        }
1113       
1114        return (len);
1115}
1116
1117static int audio_dev_open = 0;
1118
1119int
1120w32sdk_audio_open(audio_desc_t ad, audio_format *fmt, audio_format *ofmt)
1121{
1122        static int virgin;
1123        WAVEFORMATEX owfx, wfx;
1124        UINT uWavIn, uWavOut;
1125       
1126        if (audio_dev_open) {
1127                debug_msg("Device not closed! Fix immediately");
1128                w32sdk_audio_close(ad);
1129        }
1130       
1131        assert(audio_format_match(fmt, ofmt));
1132        if (fmt->encoding != DEV_S16) {
1133                return FALSE; /* Only support L16 for time being */
1134        }
1135       
1136        if (mixGetInputInfo(ad, &uWavIn, &dwRecLineID) != TRUE) {
1137                debug_msg("Could not get wave in or mixer destination for mix %u\n", ad);
1138                return FALSE;
1139        }
1140
1141        if (mixGetOutputInfo(ad, &uWavOut, &dwVolLineID) != TRUE) {
1142                debug_msg("Could not get wave out or mixer destination for mix %u\n", ad);
1143                return FALSE;
1144        }
1145       
1146        if (mixSetup(ad) == FALSE) {
1147                return FALSE; /* Could not secure mixer */
1148        }
1149
1150        mixSaveControls(ad, &control_list);
1151
1152        wfx.wFormatTag      = WAVE_FORMAT_PCM;
1153        wfx.nChannels       = (WORD)fmt->channels;
1154        wfx.nSamplesPerSec  = fmt->sample_rate;
1155        wfx.wBitsPerSample  = (WORD)fmt->bits_per_sample;
1156        smplsz              = wfx.wBitsPerSample / 8;
1157        wfx.nAvgBytesPerSec = wfx.nChannels * wfx.nSamplesPerSec * smplsz;
1158        wfx.nBlockAlign     = (WORD)(wfx.nChannels * smplsz);
1159        wfx.cbSize          = 0;
1160       
1161        memcpy(&owfx, &wfx, sizeof(wfx));
1162       
1163        /* Use 1 sec device buffer */   
1164        blksz  = fmt->bytes_per_block;
1165        nblks  = wfx.nAvgBytesPerSec / blksz;
1166       
1167        if (w32sdk_audio_open_in(uWavIn, &wfx) == FALSE){
1168                debug_msg("Open input failed\n");
1169                return FALSE;
1170        }
1171       
1172        assert(memcmp(&owfx, &wfx, sizeof(WAVEFORMATEX)) == 0);
1173       
1174        if (w32sdk_audio_open_out(uWavOut, &wfx) == FALSE) {
1175                debug_msg("Open output failed\n");
1176                w32sdk_audio_close_in();
1177                return FALSE;
1178        }
1179       
1180        if (!have_probed[ad]) {
1181                have_probed[ad] = w32sdk_probe_formats(ad);
1182        }
1183       
1184        /* because i've seen these get corrupted... */
1185        assert(memcmp(&owfx, &wfx, sizeof(WAVEFORMATEX)) == 0);
1186       
1187        switch(thread_pri) {
1188        case 1:
1189                SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
1190                debug_msg("Above Normal Priority\n");
1191                break;
1192        case 2:
1193                SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
1194                debug_msg("Time Critical Priority\n");
1195                break;
1196        case 3:
1197                SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
1198                debug_msg("Highest Thread Priority\n"); /* Kiss all processes bye-bye ;-) */
1199                break;
1200        default:
1201                break;
1202        }
1203       
1204        audio_dev_open = TRUE;
1205        return TRUE;
1206}
1207
1208void
1209w32sdk_audio_close(audio_desc_t ad)
1210{
1211        UNUSED(ad);
1212       
1213        debug_msg("Closing input device.\n");
1214        w32sdk_audio_close_in();
1215       
1216        debug_msg("Closing output device.\n");
1217        w32sdk_audio_close_out();
1218       
1219        if (input_ports != NULL) {
1220                xfree(input_ports);
1221                input_ports = NULL;
1222        }
1223       
1224        if (loop_ports != NULL) {
1225                xfree(loop_ports);
1226                loop_ports = NULL;
1227        }
1228       
1229        mixRestoreControls(ad, &control_list);
1230
1231        audio_dev_open = FALSE;
1232}
1233
1234int
1235w32sdk_audio_duplex(audio_desc_t ad)
1236{
1237        UNUSED(ad);
1238        return (TRUE);
1239}
1240
1241void
1242w32sdk_audio_drain(audio_desc_t ad)
1243{
1244        while(read_curr->dwFlags & WHDR_DONE) {
1245                read_curr->dwFlags &= ~WHDR_DONE;
1246                error = waveInAddBuffer(shWaveIn, read_curr, sizeof(WAVEHDR));
1247                if (error) {
1248                        waveInGetErrorText(error, errorText, sizeof(errorText));
1249                        debug_msg("waveInAddBuffer: (%d) %s\n", error, errorText);
1250                        exit(1);
1251                }
1252                read_curr++;
1253                if (read_curr == read_hdrs + nblks) read_curr = read_hdrs;
1254                if (audio_ready > 0) audio_ready--;     
1255        }
1256        assert(audio_ready == 0);
1257}
1258
1259void
1260w32sdk_audio_non_block(audio_desc_t ad)
1261{
1262        UNUSED(ad);
1263        debug_msg("Windows audio interface is asynchronous!\n");
1264}
1265
1266void
1267w32sdk_audio_block(audio_desc_t ad)
1268{
1269        UNUSED(ad);
1270        debug_msg("Windows audio interface is asynchronous!\n");
1271}
1272
1273void
1274w32sdk_audio_set_ogain(audio_desc_t ad, int level)
1275{
1276        DWORD   vol;
1277       
1278        UNUSED(ad);
1279       
1280        play_vol = level;
1281       
1282        if (shWaveOut == 0)
1283                return;
1284       
1285        level = rat_to_device(level);
1286        if (level >= 255)
1287                level = (short)-1;
1288        else
1289                level <<= 8;
1290        vol = level | (level << 16);
1291       
1292        error = waveOutSetVolume(shWaveOut, vol);
1293        if (error) {
1294                waveOutGetErrorText(error, errorText, sizeof(errorText));
1295                debug_msg("Win32Audio: waveOutSetVolume: %s\n", errorText);
1296        }
1297}
1298
1299int
1300w32sdk_audio_get_ogain(audio_desc_t ad)
1301{
1302        DWORD   vol;
1303       
1304        UNUSED(ad);
1305       
1306        if (shWaveOut == 0)
1307                return (play_vol);
1308       
1309        error = waveOutGetVolume(shWaveOut, &vol);
1310        if (error) {
1311                waveOutGetErrorText(error, errorText, sizeof(errorText));
1312                debug_msg("Win32Audio: waveOutGetVolume Error: %s\n", errorText);
1313                return (0);
1314        } else
1315                return (device_to_rat(vol & 0xff));
1316}
1317
1318void
1319w32sdk_audio_loopback(audio_desc_t ad, int gain)
1320{
1321        UNUSED(ad);
1322       
1323        nLoopGain = gain;
1324}
1325
1326#define WIN32_SPEAKER 0x101010
1327static audio_port_details_t outports[] = {
1328        { WIN32_SPEAKER, AUDIO_PORT_SPEAKER}
1329};
1330#define NUM_OPORTS (sizeof(outports)/sizeof(outports[0]))
1331
1332void
1333w32sdk_audio_oport_set(audio_desc_t ad, audio_port_t port)
1334{
1335        UNUSED(ad);
1336        UNUSED(port);
1337}
1338
1339/* Return selected output port */
1340audio_port_t
1341w32sdk_audio_oport_get(audio_desc_t ad)
1342{
1343        UNUSED(ad);
1344        return (WIN32_SPEAKER);
1345}
1346
1347int
1348w32sdk_audio_oport_count(audio_desc_t ad)
1349{
1350        UNUSED(ad);
1351        return (int)NUM_OPORTS;
1352}
1353
1354const audio_port_details_t*
1355w32sdk_audio_oport_details(audio_desc_t ad, int idx)
1356{
1357        UNUSED(ad);
1358        assert(idx >= 0 && idx < NUM_OPORTS);
1359        return &outports[idx];
1360}
1361
1362void 
1363w32sdk_audio_iport_set(audio_desc_t ad, audio_port_t port)
1364{
1365        char portname[MIXER_LONG_NAME_CHARS+1];
1366        int i, j, gain;
1367        UNUSED(ad);
1368       
1369        for(i = 0; i < n_input_ports; i++) {
1370                if (input_ports[i].port == port) {
1371                        /* save gain */
1372                        gain = mixerGetLineGain((HMIXEROBJ)hMixer, input_ports[iport].port);
1373                        debug_msg("Gain %d\n", gain);
1374                        if (mixerGetLineName((HMIXEROBJ)hMixer, input_ports[i].port, portname, MIXER_LONG_NAME_CHARS)) {
1375                                mixerEnableInputLine((HMIXEROBJ)hMixer, portname);
1376                        }
1377                        mixerSetLineGain((HMIXEROBJ)hMixer, input_ports[i].port, gain);
1378                       
1379                        /* Do loopback */
1380                        for(j = 0; j < n_loop_ports && nLoopGain != 0; j++) {
1381                                if (strcmp(loop_ports[j].name, input_ports[i].name) == 0) {
1382                                        mixerEnableOutputLine((HMIXEROBJ)hMixer, loop_ports[j].port, 1);
1383                                        /* mixerSetLineGain((HMIXEROBJ)hMixer, loop_ports[j].port, nLoopGain); */
1384                                }
1385                        }
1386                        iport = i;
1387                        return;
1388                }
1389        }
1390        debug_msg("Port %d not found\n", port);
1391}
1392
1393/* Return selected input port */
1394audio_port_t
1395w32sdk_audio_iport_get(audio_desc_t ad)
1396{
1397        UNUSED(ad);
1398        return input_ports[iport].port;
1399}
1400
1401int
1402w32sdk_audio_iport_count(audio_desc_t ad)
1403{
1404        UNUSED(ad);
1405        return n_input_ports;
1406}
1407
1408const audio_port_details_t*
1409w32sdk_audio_iport_details(audio_desc_t ad, int idx)
1410{
1411        UNUSED(ad);
1412        assert(idx >= 0 && idx < n_input_ports);
1413        return &input_ports[idx];
1414}
1415
1416void
1417w32sdk_audio_set_igain(audio_desc_t ad, int level)
1418{
1419        UNUSED(ad);
1420        assert(iport >= 0 && iport < n_input_ports);
1421        mixerSetLineGain((HMIXEROBJ)hMixer, input_ports[iport].port, level);
1422}
1423
1424int
1425w32sdk_audio_get_igain(audio_desc_t ad)
1426{
1427        UNUSED(ad);
1428        assert(iport >= 0 && iport < n_input_ports);
1429        return mixerGetLineGain((HMIXEROBJ)hMixer, input_ports[iport].port);
1430}
1431
1432
1433void
1434w32sdk_audio_wait_for(audio_desc_t ad, int delay_ms)
1435{
1436        DWORD   dwPeriod;
1437        int cnt = 4;
1438       
1439        dwPeriod = (DWORD)delay_ms/2;
1440        /* The blocks we are passing to the audio interface are of duration dwPeriod.
1441        * dwPeriod is usually around 20ms (8kHz), but mmtask often doesn't give
1442        * us audio that often, more like every 40ms.  In order to make UI more responsive we
1443        * block for half specified delay as the process of blocking seems to incur noticeable
1444        * delay.  If anyone has more time this is worth looking into.
1445        */
1446       
1447        while (!w32sdk_audio_is_ready(ad) && cnt--) {
1448                Sleep(dwPeriod);
1449        }
1450}
1451
1452/* Probing support */
1453
1454static audio_format af_sup[W32SDK_MAX_DEVICES][10];
1455static int          n_af_sup[W32SDK_MAX_DEVICES];
1456
1457int
1458w32sdk_probe_format(int rate, int channels)
1459{
1460        WAVEFORMATEX wfx;
1461       
1462        wfx.cbSize = 0; /* PCM format */
1463        wfx.wFormatTag      = WAVE_FORMAT_PCM;
1464        wfx.wBitsPerSample  = 16; /* 16 bit linear */
1465        wfx.nChannels       = channels;
1466        wfx.nSamplesPerSec  = rate;
1467        wfx.nBlockAlign     = wfx.wBitsPerSample / 8 * wfx.nChannels;
1468        wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
1469       
1470        if (waveInOpen(NULL, (UINT)shWaveIn, &wfx, (UINT)NULL, (UINT)NULL, WAVE_FORMAT_QUERY)) {
1471                debug_msg("%d %d supported\n", rate, channels);
1472                return TRUE;
1473        }
1474       
1475        debug_msg("%d %d not supported\n", rate, channels);
1476        return FALSE;     
1477}
1478
1479int 
1480w32sdk_probe_formats(audio_desc_t ad)
1481{
1482        int rate, channels;
1483
1484        for (rate = 8000; rate <= 48000; rate+=8000) {
1485                if (rate == 24000 || rate == 40000) continue;
1486                for(channels = 1; channels <= 2; channels++) {
1487                        if (w32sdk_probe_format(rate, channels)) {
1488                                af_sup[ad][n_af_sup[ad]].sample_rate = rate;
1489                                af_sup[ad][n_af_sup[ad]].channels    = channels;
1490                                n_af_sup[ad]++;
1491                        }
1492                }
1493        }
1494        return (n_af_sup[ad] ? TRUE : FALSE); /* Managed to find at least 1 we support */
1495                                              /* We have this test since if we cannot get device now (because in use elsewhere)
1496        * we will want to test it later */
1497}
1498
1499int
1500w32sdk_audio_supports(audio_desc_t ad, audio_format *paf)
1501{
1502        int i;
1503        for(i = 0; i < n_af_sup[ad]; i++) {
1504                if (af_sup[ad][i].sample_rate  == paf->sample_rate &&
1505                        af_sup[ad][i].channels == paf->channels) {
1506                        return TRUE;
1507                }
1508        }
1509        return FALSE;
1510}
1511
1512int
1513w32sdk_get_device_count()
1514{
1515        /* We are only interested in devices with mixers */
1516        return (int)mixerGetNumDevs();
1517}
1518
1519static char tmpname[MAXPNAMELEN];
1520
1521char *
1522w32sdk_get_device_name(int idx)
1523{
1524        MIXERCAPS mc;
1525       
1526        if ((UINT)idx < mixerGetNumDevs()) {
1527                mixerGetDevCaps((UINT)idx, &mc, sizeof(mc));
1528                strcpy(tmpname, mc.szPname);
1529                return tmpname;
1530        }
1531        return NULL;
1532}
1533#endif /* WIN32 */
Note: See TracBrowser for help on using the browser.