2 * Audio management UI code
4 * Copyright 2004 Chris Morgan
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #define NONAMELESSSTRUCT
23 #define NONAMELESSUNION
26 #include "wine/port.h"
37 #include <wine/debug.h>
51 WINE_DEFAULT_DEBUG_CHANNEL(winecfg
);
53 typedef DWORD (WINAPI
* MessagePtr
)(UINT
, UINT
, DWORD
, DWORD
, DWORD
);
55 static const char* DSound_HW_Accels
[] = {
63 /* Select the correct entry in the combobox based on drivername */
64 static void selectAudioDriver(HWND hDlg
, const char *drivername
)
67 const AUDIO_DRIVER
*pAudioDrv
= NULL
;
69 if ((pAudioDrv
= getAudioDrivers()))
71 for (i
= 0; *pAudioDrv
->szName
; i
++, pAudioDrv
++)
73 if (!strcmp (pAudioDrv
->szDriver
, drivername
))
75 set_reg_key(config_key
, "Drivers", "Audio", (char *) pAudioDrv
->szDriver
);
76 SendMessage(GetParent(hDlg
), PSM_CHANGED
, (WPARAM
) hDlg
, 0); /* enable apply button */
77 SendDlgItemMessage(hDlg
, IDC_AUDIO_DRIVER
, CB_SETCURSEL
,
84 static void configureAudioDriver(HWND hDlg
, const char *drivername
)
87 const AUDIO_DRIVER
*pAudioDrv
= NULL
;
89 if ((pAudioDrv
= getAudioDrivers()))
91 for (i
= 0; *pAudioDrv
->szName
; i
++, pAudioDrv
++)
93 if (!strcmp (pAudioDrv
->szDriver
, drivername
))
95 if (strlen(pAudioDrv
->szDriver
) != 0)
98 char wine_driver
[MAX_NAME_LENGTH
+ 8];
99 sprintf(wine_driver
, "wine%s.drv", pAudioDrv
->szDriver
);
100 hdrvr
= OpenDriverA(wine_driver
, 0, 0);
103 if (SendDriverMessage(hdrvr
, DRV_QUERYCONFIGURE
, 0, 0) != 0)
107 dci
.dwDCISize
= sizeof (dci
);
108 dci
.lpszDCISectionName
= NULL
;
109 dci
.lpszDCIAliasName
= NULL
;
110 lRes
= SendDriverMessage(hdrvr
, DRV_CONFIGURE
, 0, (LONG
)&dci
);
112 CloseDriver(hdrvr
, 0, 0);
117 sprintf(str
, "Couldn't open %s!", wine_driver
);
118 MessageBox(NULL
, str
, "Fixme", MB_OK
| MB_ICONERROR
);
127 static void initAudioDeviceTree(HWND hDlg
)
129 const AUDIO_DRIVER
*pAudioDrv
= NULL
;
131 TVINSERTSTRUCT insert
;
132 HTREEITEM root
, driver
[10];
135 tree
= GetDlgItem(hDlg
, IDC_AUDIO_TREE
);
140 SetWindowLong(tree
, GWL_STYLE
, GetWindowLong(tree
, GWL_STYLE
) | TVS_HASBUTTONS
| TVS_HASLINES
| TVS_LINESATROOT
);
142 insert
.hParent
= TVI_ROOT
;
143 insert
.hInsertAfter
= TVI_LAST
;
144 insert
.u
.item
.mask
= TVIF_TEXT
| TVIF_CHILDREN
;
145 insert
.u
.item
.pszText
= "Sound Drivers";
146 insert
.u
.item
.cChildren
= 1;
148 root
= (HTREEITEM
)SendDlgItemMessage(hDlg
, IDC_AUDIO_TREE
, TVM_INSERTITEM
, 0, (LPARAM
)&insert
);
150 pAudioDrv
= getAudioDrivers();
152 for (i
= 0; *pAudioDrv
->szName
; i
++, pAudioDrv
++) {
157 if (strlen(pAudioDrv
->szDriver
) == 0)
160 sprintf(name
, "wine%s.drv", pAudioDrv
->szDriver
);
161 sprintf(text
, "%s Driver", pAudioDrv
->szName
);
163 hdrv
= OpenDriverA(name
, 0, 0);
164 if (hdrv
== 0) /* no driver loaded */
166 insert
.hParent
= root
;
167 insert
.u
.item
.mask
= TVIF_TEXT
;
168 insert
.u
.item
.pszText
= text
;
170 driver
[i
] = (HTREEITEM
)SendDlgItemMessage(hDlg
, IDC_AUDIO_TREE
, TVM_INSERTITEM
, 0, (LPARAM
)&insert
);
176 lib
= LoadLibrary(name
);
179 int num_wod
= 0, num_wid
= 0, num_mod
= 0, num_mid
= 0, num_aux
= 0, num_mxd
= 0;
180 MessagePtr wodMessagePtr
= (MessagePtr
)GetProcAddress(lib
, "wodMessage");
181 MessagePtr widMessagePtr
= (MessagePtr
)GetProcAddress(lib
, "widMessage");
182 MessagePtr modMessagePtr
= (MessagePtr
)GetProcAddress(lib
, "modMessage");
183 MessagePtr midMessagePtr
= (MessagePtr
)GetProcAddress(lib
, "midMessage");
184 MessagePtr auxMessagePtr
= (MessagePtr
)GetProcAddress(lib
, "auxMessage");
185 MessagePtr mxdMessagePtr
= (MessagePtr
)GetProcAddress(lib
, "mxdMessage");
188 num_wod
= wodMessagePtr(0, WODM_GETNUMDEVS
, 0, 0, 0);
191 num_wid
= widMessagePtr(0, WIDM_GETNUMDEVS
, 0, 0, 0);
194 num_mod
= modMessagePtr(0, MODM_GETNUMDEVS
, 0, 0, 0);
197 num_mid
= midMessagePtr(0, MIDM_GETNUMDEVS
, 0, 0, 0);
200 num_aux
= auxMessagePtr(0, AUXDM_GETNUMDEVS
, 0, 0, 0);
203 num_mxd
= mxdMessagePtr(0, MXDM_GETNUMDEVS
, 0, 0, 0);
205 if (num_wod
== 0 && num_wid
== 0 && num_mod
== 0 && num_mid
== 0 && num_aux
== 0 && num_mxd
== 0)
207 insert
.hParent
= root
;
208 insert
.u
.item
.mask
= TVIF_TEXT
;
209 insert
.u
.item
.pszText
= text
;
211 driver
[i
] = (HTREEITEM
)SendDlgItemMessage(hDlg
, IDC_AUDIO_TREE
, TVM_INSERTITEM
, 0, (LPARAM
)&insert
);
217 insert
.hParent
= root
;
218 insert
.u
.item
.mask
= TVIF_TEXT
| TVIF_CHILDREN
;
219 insert
.u
.item
.pszText
= text
;
220 insert
.u
.item
.cChildren
= 1;
222 driver
[i
] = (HTREEITEM
)SendDlgItemMessage(hDlg
, IDC_AUDIO_TREE
, TVM_INSERTITEM
, 0, (LPARAM
)&insert
);
226 insert
.hParent
= driver
[i
];
227 insert
.u
.item
.mask
= TVIF_TEXT
| TVIF_CHILDREN
;
228 insert
.u
.item
.pszText
= "Wave Out Devices";
229 insert
.u
.item
.cChildren
= 1;
231 type
= (HTREEITEM
)SendDlgItemMessage(hDlg
, IDC_AUDIO_TREE
, TVM_INSERTITEM
, 0, (LPARAM
)&insert
);
233 for (j
= 0; j
< num_wod
; j
++)
236 char szPname
[MAXPNAMELEN
];
238 wodMessagePtr(j
, WODM_GETDEVCAPS
, 0, (DWORD
)&caps
, sizeof(caps
));
239 WideCharToMultiByte(CP_ACP
, 0, caps
.szPname
, -1, szPname
, MAXPNAMELEN
, 0, 0);
241 insert
.hParent
= type
;
242 insert
.u
.item
.mask
= TVIF_TEXT
;
243 insert
.u
.item
.pszText
= szPname
;
245 SendDlgItemMessage(hDlg
, IDC_AUDIO_TREE
, TVM_INSERTITEM
, 0, (LPARAM
)&insert
);
251 insert
.hParent
= driver
[i
];
252 insert
.u
.item
.mask
= TVIF_TEXT
| TVIF_CHILDREN
;
253 insert
.u
.item
.pszText
= "Wave In Devices";
254 insert
.u
.item
.cChildren
= 1;
256 type
= (HTREEITEM
)SendDlgItemMessage(hDlg
, IDC_AUDIO_TREE
, TVM_INSERTITEM
, 0, (LPARAM
)&insert
);
258 for (j
= 0; j
< num_wid
; j
++)
261 char szPname
[MAXPNAMELEN
];
263 widMessagePtr(j
, WIDM_GETDEVCAPS
, 0, (DWORD
)&caps
, sizeof(caps
));
264 WideCharToMultiByte(CP_ACP
, 0, caps
.szPname
, -1, szPname
, MAXPNAMELEN
, 0, 0);
266 insert
.hParent
= type
;
267 insert
.u
.item
.mask
= TVIF_TEXT
;
268 insert
.u
.item
.pszText
= szPname
;
270 SendDlgItemMessage(hDlg
, IDC_AUDIO_TREE
, TVM_INSERTITEM
, 0, (LPARAM
)&insert
);
276 insert
.hParent
= driver
[i
];
277 insert
.u
.item
.mask
= TVIF_TEXT
| TVIF_CHILDREN
;
278 insert
.u
.item
.pszText
= "MIDI Out Devices";
279 insert
.u
.item
.cChildren
= 1;
281 type
= (HTREEITEM
)SendDlgItemMessage(hDlg
, IDC_AUDIO_TREE
, TVM_INSERTITEM
, 0, (LPARAM
)&insert
);
283 for (j
= 0; j
< num_mod
; j
++)
286 char szPname
[MAXPNAMELEN
];
288 modMessagePtr(j
, MODM_GETDEVCAPS
, 0, (DWORD
)&caps
, sizeof(caps
));
289 WideCharToMultiByte(CP_ACP
, 0, caps
.szPname
, -1, szPname
, MAXPNAMELEN
, 0, 0);
291 insert
.hParent
= type
;
292 insert
.u
.item
.mask
= TVIF_TEXT
;
293 insert
.u
.item
.pszText
= szPname
;
295 SendDlgItemMessage(hDlg
, IDC_AUDIO_TREE
, TVM_INSERTITEM
, 0, (LPARAM
)&insert
);
301 insert
.hParent
= driver
[i
];
302 insert
.u
.item
.mask
= TVIF_TEXT
| TVIF_CHILDREN
;
303 insert
.u
.item
.pszText
= "MIDI In Devices";
304 insert
.u
.item
.cChildren
= 1;
306 type
= (HTREEITEM
)SendDlgItemMessage(hDlg
, IDC_AUDIO_TREE
, TVM_INSERTITEM
, 0, (LPARAM
)&insert
);
308 for (j
= 0; j
< num_mid
; j
++)
311 char szPname
[MAXPNAMELEN
];
313 midMessagePtr(j
, MIDM_GETDEVCAPS
, 0, (DWORD
)&caps
, sizeof(caps
));
314 WideCharToMultiByte(CP_ACP
, 0, caps
.szPname
, -1, szPname
, MAXPNAMELEN
, 0, 0);
316 insert
.hParent
= type
;
317 insert
.u
.item
.mask
= TVIF_TEXT
;
318 insert
.u
.item
.pszText
= szPname
;
320 SendDlgItemMessage(hDlg
, IDC_AUDIO_TREE
, TVM_INSERTITEM
, 0, (LPARAM
)&insert
);
326 insert
.hParent
= driver
[i
];
327 insert
.u
.item
.mask
= TVIF_TEXT
| TVIF_CHILDREN
;
328 insert
.u
.item
.pszText
= "Aux Devices";
329 insert
.u
.item
.cChildren
= 1;
331 type
= (HTREEITEM
)SendDlgItemMessage(hDlg
, IDC_AUDIO_TREE
, TVM_INSERTITEM
, 0, (LPARAM
)&insert
);
333 for (j
= 0; j
< num_aux
; j
++)
336 char szPname
[MAXPNAMELEN
];
338 auxMessagePtr(j
, AUXDM_GETDEVCAPS
, 0, (DWORD
)&caps
, sizeof(caps
));
339 WideCharToMultiByte(CP_ACP
, 0, caps
.szPname
, -1, szPname
, MAXPNAMELEN
, 0, 0);
341 insert
.hParent
= type
;
342 insert
.u
.item
.mask
= TVIF_TEXT
;
343 insert
.u
.item
.pszText
= szPname
;
345 SendDlgItemMessage(hDlg
, IDC_AUDIO_TREE
, TVM_INSERTITEM
, 0, (LPARAM
)&insert
);
351 insert
.hParent
= driver
[i
];
352 insert
.u
.item
.mask
= TVIF_TEXT
| TVIF_CHILDREN
;
353 insert
.u
.item
.pszText
= "Mixer Devices";
354 insert
.u
.item
.cChildren
= 1;
356 type
= (HTREEITEM
)SendDlgItemMessage(hDlg
, IDC_AUDIO_TREE
, TVM_INSERTITEM
, 0, (LPARAM
)&insert
);
358 for (j
= 0; j
< num_mxd
; j
++)
361 char szPname
[MAXPNAMELEN
];
363 mxdMessagePtr(j
, MXDM_GETDEVCAPS
, 0, (DWORD
)&caps
, sizeof(caps
));
364 WideCharToMultiByte(CP_ACP
, 0, caps
.szPname
, -1, szPname
, MAXPNAMELEN
, 0, 0);
366 insert
.hParent
= type
;
367 insert
.u
.item
.mask
= TVIF_TEXT
;
368 insert
.u
.item
.pszText
= szPname
;
370 SendDlgItemMessage(hDlg
, IDC_AUDIO_TREE
, TVM_INSERTITEM
, 0, (LPARAM
)&insert
);
379 SendDlgItemMessage(hDlg
, IDC_AUDIO_TREE
, TVM_SELECTITEM
, 0, 0);
380 SendDlgItemMessage(hDlg
, IDC_AUDIO_TREE
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)root
);
381 for (j
= 0; j
< i
; j
++)
382 SendDlgItemMessage(hDlg
, IDC_AUDIO_TREE
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)driver
[j
]);
385 static void initAudioDlg (HWND hDlg
)
387 char *curAudioDriver
= get_reg_key(config_key
, "Drivers", "Audio", "alsa");
388 const AUDIO_DRIVER
*pAudioDrv
= NULL
;
394 pAudioDrv
= getAudioDrivers ();
395 for (i
= 0; *pAudioDrv
->szName
; i
++, pAudioDrv
++) {
396 SendDlgItemMessage (hDlg
, IDC_AUDIO_DRIVER
, CB_ADDSTRING
,
397 0, (LPARAM
) pAudioDrv
->szName
);
398 if (!strcmp (pAudioDrv
->szDriver
, curAudioDriver
)) {
399 SendDlgItemMessage(hDlg
, IDC_AUDIO_DRIVER
, CB_SETCURSEL
, i
, 0);
403 initAudioDeviceTree(hDlg
);
405 SendDlgItemMessage(hDlg
, IDC_DSOUND_HW_ACCEL
, CB_RESETCONTENT
, 0, 0);
406 for (i
= 0; NULL
!= DSound_HW_Accels
[i
]; ++i
) {
407 SendDlgItemMessage(hDlg
, IDC_DSOUND_HW_ACCEL
, CB_ADDSTRING
, 0, (LPARAM
) DSound_HW_Accels
[i
]);
409 buf
= get_reg_key(config_key
, keypath("DirectSound"), "HardwareAcceleration", "Full");
410 for (i
= 0; NULL
!= DSound_HW_Accels
[i
]; ++i
) {
411 if (strcmp(buf
, DSound_HW_Accels
[i
]) == 0) {
412 SendDlgItemMessage(hDlg
, IDC_DSOUND_HW_ACCEL
, CB_SETCURSEL
, i
, 0);
416 if (NULL
== DSound_HW_Accels
[i
]) {
417 WINE_ERR("Invalid Direct Sound HW Accel read from registry (%s)\n", buf
);
419 HeapFree(GetProcessHeap(), 0, buf
);
421 buf
= get_reg_key(config_key
, keypath("DirectSound"), "EmulDriver", "N");
422 if (IS_OPTION_TRUE(*buf
))
423 CheckDlgButton(hDlg
, IDC_DSOUND_DRV_EMUL
, BST_CHECKED
);
425 CheckDlgButton(hDlg
, IDC_DSOUND_DRV_EMUL
, BST_UNCHECKED
);
426 HeapFree(GetProcessHeap(), 0, buf
);
430 static const char *audioAutoDetect(void)
432 const char *driversFound
[10];
433 const char *name
[10];
435 const AUDIO_DRIVER
*pAudioDrv
= NULL
;
438 pAudioDrv
= getAudioDrivers();
440 for (i
= 0; *pAudioDrv
->szName
; i
++, pAudioDrv
++)
442 if (strlen(pAudioDrv
->szDriver
))
445 char driver
[MAX_PATH
];
447 sprintf(driver
, "wine%s.drv", pAudioDrv
->szDriver
);
449 if ((hdrv
= OpenDriverA(driver
, 0, 0)))
451 CloseDriver(hdrv
, 0, 0);
452 driversFound
[numFound
] = pAudioDrv
->szDriver
;
453 name
[numFound
] = pAudioDrv
->szName
;
461 MessageBox(NULL
, "Could not detect any audio devices/servers", "Failed", MB_OK
);
466 /* TODO: possibly smarter handling of multiple drivers? */
468 sprintf(text
, "Found ");
469 for(i
=0;i
<numFound
;i
++)
471 strcat(text
, name
[i
]);
475 MessageBox(NULL
, (LPCTSTR
)text
, "Successful", MB_OK
);
476 return driversFound
[0];
482 AudioDlgProc (HWND hDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
486 switch (LOWORD(wParam
)) {
487 case IDC_AUDIO_AUTODETECT
:
488 selectAudioDriver(hDlg
, audioAutoDetect());
490 case IDC_AUDIO_DRIVER
:
491 if ((HIWORD(wParam
) == CBN_SELCHANGE
) ||
492 (HIWORD(wParam
) == CBN_SELCHANGE
))
494 const AUDIO_DRIVER
*pAudioDrv
= getAudioDrivers();
495 int selected_driver
= SendDlgItemMessage(hDlg
, IDC_AUDIO_DRIVER
, CB_GETCURSEL
, 0, 0);
496 selectAudioDriver(hDlg
, (char*)pAudioDrv
[selected_driver
].szDriver
);
499 case IDC_AUDIO_CONFIGURE
:
501 const AUDIO_DRIVER
*pAudioDrv
= getAudioDrivers();
502 int selected_driver
= SendDlgItemMessage(hDlg
, IDC_AUDIO_DRIVER
, CB_GETCURSEL
, 0, 0);
503 configureAudioDriver(hDlg
, (char*)pAudioDrv
[selected_driver
].szDriver
);
506 case IDC_AUDIO_CONTROL_PANEL
:
507 MessageBox(NULL
, "Launching audio control panel not implemented yet!", "Fixme", MB_OK
| MB_ICONERROR
);
509 case IDC_DSOUND_HW_ACCEL
:
510 if (HIWORD(wParam
) == CBN_SELCHANGE
) {
511 int selected_dsound_accel
;
512 SendMessage(GetParent(hDlg
), PSM_CHANGED
, 0, 0);
513 selected_dsound_accel
= SendDlgItemMessage(hDlg
, IDC_DSOUND_HW_ACCEL
, CB_GETCURSEL
, 0, 0);
514 set_reg_key(config_key
, keypath("DirectSound"), "HardwareAcceleration", DSound_HW_Accels
[selected_dsound_accel
]);
517 case IDC_DSOUND_DRV_EMUL
:
518 if (HIWORD(wParam
) == BN_CLICKED
) {
519 SendMessage(GetParent(hDlg
), PSM_CHANGED
, 0, 0);
520 if (IsDlgButtonChecked(hDlg
, IDC_DSOUND_DRV_EMUL
) == BST_CHECKED
)
521 set_reg_key(config_key
, keypath("DirectSound"), "EmulDriver", "Y");
523 set_reg_key(config_key
, keypath("DirectSound"), "EmulDriver", "N");
530 set_window_title(hDlg
);
534 switch(((LPNMHDR
)lParam
)->code
) {
536 SetWindowLongPtr(hDlg
, DWLP_MSGRESULT
, FALSE
);
540 SetWindowLongPtr(hDlg
, DWLP_MSGRESULT
, PSNRET_NOERROR
);