winecfg: Fix compilation on gcc 2.95 (no nameless unions).
[wine/multimedia.git] / programs / winecfg / audio.c
blob232a41ca2fe8124660c1800069ab63244bfcf644
1 /*
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
25 #include "config.h"
26 #include "wine/port.h"
28 #include <assert.h>
29 #include <stdarg.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
34 #include <windef.h>
35 #include <winbase.h>
36 #include <winreg.h>
37 #include <wine/debug.h>
38 #include <shellapi.h>
39 #include <objbase.h>
40 #include <shlguid.h>
41 #include <shlwapi.h>
42 #include <shlobj.h>
43 #include <mmsystem.h>
44 #include <mmreg.h>
45 #include <mmsystem.h>
46 #include <mmddk.h>
48 #include "winecfg.h"
49 #include "resource.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
53 typedef DWORD (WINAPI * MessagePtr)(UINT, UINT, DWORD, DWORD, DWORD);
55 static const char* DSound_HW_Accels[] = {
56 "Full",
57 "Standard",
58 "Basic",
59 "Emulation",
60 NULL
63 /* Select the correct entry in the combobox based on drivername */
64 static void selectAudioDriver(HWND hDlg, const char *drivername)
66 int i;
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,
78 (WPARAM) i, 0);
84 static void configureAudioDriver(HWND hDlg, const char *drivername)
86 int i;
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)
97 HDRVR hdrvr;
98 char wine_driver[MAX_NAME_LENGTH + 8];
99 sprintf(wine_driver, "wine%s.drv", pAudioDrv->szDriver);
100 hdrvr = OpenDriverA(wine_driver, 0, 0);
101 if (hdrvr != 0)
103 if (SendDriverMessage(hdrvr, DRV_QUERYCONFIGURE, 0, 0) != 0)
105 DRVCONFIGINFO dci;
106 LONG lRes;
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);
114 else
116 char str[1024];
117 sprintf(str, "Couldn't open %s!", wine_driver);
118 MessageBox(NULL, str, "Fixme", MB_OK | MB_ICONERROR);
121 break;
127 static void initAudioDeviceTree(HWND hDlg)
129 const AUDIO_DRIVER *pAudioDrv = NULL;
130 int i, j;
131 TVINSERTSTRUCT insert;
132 HTREEITEM root, driver[10];
133 HWND tree = NULL;
135 tree = GetDlgItem(hDlg, IDC_AUDIO_TREE);
137 if (!tree)
138 return;
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++) {
153 HDRVR hdrv;
154 char name[MAX_PATH];
155 char text[MAX_PATH];
157 if (strlen(pAudioDrv->szDriver) == 0)
158 continue;
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);
172 else
174 HINSTANCE lib;
176 lib = LoadLibrary(name);
177 if (lib)
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");
187 if (wodMessagePtr)
188 num_wod = wodMessagePtr(0, WODM_GETNUMDEVS, 0, 0, 0);
190 if (widMessagePtr)
191 num_wid = widMessagePtr(0, WIDM_GETNUMDEVS, 0, 0, 0);
193 if (modMessagePtr)
194 num_mod = modMessagePtr(0, MODM_GETNUMDEVS, 0, 0, 0);
196 if (midMessagePtr)
197 num_mid = midMessagePtr(0, MIDM_GETNUMDEVS, 0, 0, 0);
199 if (auxMessagePtr)
200 num_aux = auxMessagePtr(0, AUXDM_GETNUMDEVS, 0, 0, 0);
202 if (mxdMessagePtr)
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);
213 else
215 HTREEITEM type;
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);
224 if (num_wod)
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++)
235 WAVEOUTCAPSW caps;
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);
249 if (num_wid)
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++)
260 WAVEINCAPSW caps;
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);
274 if (num_mod)
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++)
285 MIDIOUTCAPSW caps;
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);
299 if (num_mid)
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++)
310 MIDIINCAPSW caps;
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);
324 if (num_aux)
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++)
335 AUXCAPSW caps;
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);
349 if (num_mxd)
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++)
360 MIXERCAPSW caps;
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);
374 FreeLibrary(lib);
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;
389 int i;
390 char* buf = NULL;
392 WINE_TRACE("\n");
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);
413 break ;
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);
424 else
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];
434 int numFound = 0;
435 const AUDIO_DRIVER *pAudioDrv = NULL;
436 int i;
438 pAudioDrv = getAudioDrivers();
440 for (i = 0; *pAudioDrv->szName; i++, pAudioDrv++)
442 if (strlen(pAudioDrv->szDriver))
444 HDRVR hdrv;
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;
454 numFound++;
459 if(numFound == 0)
461 MessageBox(NULL, "Could not detect any audio devices/servers", "Failed", MB_OK);
462 return "";
464 else
466 /* TODO: possibly smarter handling of multiple drivers? */
467 char text[128];
468 sprintf(text, "Found ");
469 for(i=0;i<numFound;i++)
471 strcat(text, name[i]);
472 if(i != numFound-1)
473 strcat(text,", ");
475 MessageBox(NULL, (LPCTSTR)text, "Successful", MB_OK);
476 return driversFound[0];
481 INT_PTR CALLBACK
482 AudioDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
484 switch (uMsg) {
485 case WM_COMMAND:
486 switch (LOWORD(wParam)) {
487 case IDC_AUDIO_AUTODETECT:
488 selectAudioDriver(hDlg, audioAutoDetect());
489 break;
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);
498 break;
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);
505 break;
506 case IDC_AUDIO_CONTROL_PANEL:
507 MessageBox(NULL, "Launching audio control panel not implemented yet!", "Fixme", MB_OK | MB_ICONERROR);
508 break;
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]);
516 break;
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");
522 else
523 set_reg_key(config_key, keypath("DirectSound"), "EmulDriver", "N");
525 break;
527 break;
529 case WM_SHOWWINDOW:
530 set_window_title(hDlg);
531 break;
533 case WM_NOTIFY:
534 switch(((LPNMHDR)lParam)->code) {
535 case PSN_KILLACTIVE:
536 SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
537 break;
538 case PSN_APPLY:
539 apply();
540 SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
541 break;
542 case PSN_SETACTIVE:
543 break;
545 break;
547 case WM_INITDIALOG:
548 initAudioDlg(hDlg);
549 break;
552 return FALSE;