1 /*
2 *
3 * PROJECT: ReactOS Multimedia Control Panel
4 * FILE: dll/cpl/mmsys/audio.c
5 * PURPOSE: ReactOS Multimedia Control Panel
6 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
7 * Johannes Anderwald <janderwald@reactos.com>
8 * Dmitry Chapyshev <dmitry@reactos.org>
9 */
10
11 #include "mmsys.h"
12
13 typedef struct _GLOBAL_DATA
14 {
15 BOOL bNoAudioOut;
16 BOOL bNoAudioIn;
17 BOOL bNoMIDIOut;
18
19 BOOL bAudioOutChanged;
20 BOOL bAudioInChanged;
21 BOOL bMIDIOutChanged;
22
23 } GLOBAL_DATA, *PGLOBAL_DATA;
24
25 VOID
InitAudioDlg(HWND hwnd,PGLOBAL_DATA pGlobalData)26 InitAudioDlg(HWND hwnd, PGLOBAL_DATA pGlobalData)
27 {
28 WAVEOUTCAPSW waveOutputPaps;
29 WAVEINCAPSW waveInputPaps;
30 MIDIOUTCAPSW midiOutCaps;
31 WCHAR szNoDevices[256];
32 UINT DevsNum;
33 UINT uIndex;
34 HWND hCB;
35 LRESULT Res;
36
37 LoadStringW(hApplet, IDS_NO_DEVICES, szNoDevices, _countof(szNoDevices));
38
39 // Init sound playback devices list
40 hCB = GetDlgItem(hwnd, IDC_DEVICE_PLAY_LIST);
41
42 DevsNum = waveOutGetNumDevs();
43 if (DevsNum < 1)
44 {
45 Res = SendMessageW(hCB, CB_ADDSTRING, 0, (LPARAM)szNoDevices);
46 SendMessageW(hCB, CB_SETCURSEL, (WPARAM)Res, 0);
47 pGlobalData->bNoAudioOut = TRUE;
48 }
49 else
50 {
51 WCHAR DefaultDevice[MAX_PATH] = {0};
52 HKEY hKey;
53 DWORD dwSize = sizeof(DefaultDevice);
54 UINT DefaultIndex = 0;
55
56 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Multimedia\\Sound Mapper", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
57 {
58 RegQueryValueExW(hKey, L"Playback", NULL, NULL, (LPBYTE)DefaultDevice, &dwSize);
59 DefaultDevice[_countof(DefaultDevice) - 1] = UNICODE_NULL;
60 RegCloseKey(hKey);
61 }
62
63 for (uIndex = 0; uIndex < DevsNum; uIndex++)
64 {
65 if (waveOutGetDevCapsW(uIndex, &waveOutputPaps, sizeof(waveOutputPaps)))
66 continue;
67
68 Res = SendMessageW(hCB, CB_ADDSTRING, 0, (LPARAM)waveOutputPaps.szPname);
69
70 if (CB_ERR != Res)
71 {
72 SendMessageW(hCB, CB_SETITEMDATA, Res, (LPARAM)uIndex);
73 if (!_wcsicmp(waveOutputPaps.szPname, DefaultDevice))
74 DefaultIndex = Res;
75 }
76 }
77 SendMessageW(hCB, CB_SETCURSEL, (WPARAM)DefaultIndex, 0);
78 }
79
80 // Init sound recording devices list
81 hCB = GetDlgItem(hwnd, IDC_DEVICE_REC_LIST);
82
83 DevsNum = waveInGetNumDevs();
84 if (DevsNum < 1)
85 {
86 Res = SendMessageW(hCB, CB_ADDSTRING, 0, (LPARAM)szNoDevices);
87 SendMessageW(hCB, CB_SETCURSEL, (WPARAM)Res, 0);
88 pGlobalData->bNoAudioIn = TRUE;
89 }
90 else
91 {
92 WCHAR DefaultDevice[MAX_PATH] = {0};
93 HKEY hKey;
94 DWORD dwSize = sizeof(DefaultDevice);
95 UINT DefaultIndex = 0;
96
97 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Multimedia\\Sound Mapper", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
98 {
99 RegQueryValueExW(hKey, L"Record", NULL, NULL, (LPBYTE)DefaultDevice, &dwSize);
100 DefaultDevice[_countof(DefaultDevice) - 1] = UNICODE_NULL;
101 RegCloseKey(hKey);
102 }
103
104
105 for (uIndex = 0; uIndex < DevsNum; uIndex++)
106 {
107 if (waveInGetDevCapsW(uIndex, &waveInputPaps, sizeof(waveInputPaps)))
108 continue;
109
110 Res = SendMessageW(hCB, CB_ADDSTRING, 0, (LPARAM)waveInputPaps.szPname);
111
112 if (CB_ERR != Res)
113 {
114 SendMessageW(hCB, CB_SETITEMDATA, Res, (LPARAM)uIndex);
115 if (!_wcsicmp(waveInputPaps.szPname, DefaultDevice))
116 DefaultIndex = Res;
117 }
118 }
119 SendMessageW(hCB, CB_SETCURSEL, (WPARAM)DefaultIndex, 0);
120 }
121
122 // Init MIDI devices list
123 hCB = GetDlgItem(hwnd, IDC_DEVICE_MIDI_LIST);
124
125 DevsNum = midiOutGetNumDevs();
126 if (DevsNum < 1)
127 {
128 Res = SendMessageW(hCB, CB_ADDSTRING, 0, (LPARAM)szNoDevices);
129 SendMessageW(hCB, CB_SETCURSEL, (WPARAM)Res, 0);
130 pGlobalData->bNoMIDIOut = TRUE;
131 }
132 else
133 {
134 WCHAR DefaultDevice[MAX_PATH] = {0};
135 HKEY hKey;
136 DWORD dwSize = sizeof(DefaultDevice);
137 UINT DefaultIndex = 0;
138
139 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia\\MIDIMap", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
140 {
141 RegQueryValueExW(hKey, L"szPname", NULL, NULL, (LPBYTE)DefaultDevice, &dwSize);
142 DefaultDevice[_countof(DefaultDevice) - 1] = UNICODE_NULL;
143 RegCloseKey(hKey);
144 }
145
146 for (uIndex = 0; uIndex < DevsNum; uIndex++)
147 {
148 if (midiOutGetDevCapsW(uIndex, &midiOutCaps, sizeof(midiOutCaps)))
149 continue;
150
151 Res = SendMessageW(hCB, CB_ADDSTRING, 0, (LPARAM)midiOutCaps.szPname);
152
153 if (CB_ERR != Res)
154 {
155 SendMessageW(hCB, CB_SETITEMDATA, Res, (LPARAM)uIndex);
156 if (!_wcsicmp(midiOutCaps.szPname, DefaultDevice))
157 DefaultIndex = Res;
158 }
159 }
160 SendMessageW(hCB, CB_SETCURSEL, (WPARAM)DefaultIndex, 0);
161 }
162 }
163
164 VOID
UpdateRegistryString(HWND hwnd,INT ctrl,LPCWSTR key,LPCWSTR value)165 UpdateRegistryString(HWND hwnd, INT ctrl, LPCWSTR key, LPCWSTR value)
166 {
167 HWND hwndCombo = GetDlgItem(hwnd, ctrl);
168 INT CurSel = SendMessageW(hwndCombo, CB_GETCURSEL, 0, 0);
169 UINT TextLen;
170 WCHAR SelectedDevice[MAX_PATH] = {0};
171 HKEY hKey;
172
173 if (CurSel == CB_ERR)
174 return;
175
176 TextLen = SendMessageW(hwndCombo, CB_GETLBTEXTLEN, CurSel, 0) + 1;
177
178 if (TextLen > _countof(SelectedDevice))
179 return;
180
181 SendMessageW(hwndCombo, CB_GETLBTEXT, CurSel, (LPARAM)SelectedDevice);
182
183 if (RegCreateKeyExW(HKEY_CURRENT_USER, key, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS)
184 return;
185
186 RegSetValueExW(hKey, value, 0, REG_SZ, (BYTE*)SelectedDevice, (wcslen(SelectedDevice) + 1) * sizeof(WCHAR));
187 RegCloseKey(hKey);
188 }
189
190 VOID
SaveAudioDlg(HWND hwnd,PGLOBAL_DATA pGlobalData)191 SaveAudioDlg(HWND hwnd, PGLOBAL_DATA pGlobalData)
192 {
193 if (pGlobalData->bAudioOutChanged)
194 {
195 UpdateRegistryString(hwnd,
196 IDC_DEVICE_PLAY_LIST,
197 L"Software\\Microsoft\\Multimedia\\Sound Mapper",
198 L"Playback");
199 }
200
201 if (pGlobalData->bAudioInChanged)
202 {
203 UpdateRegistryString(hwnd,
204 IDC_DEVICE_REC_LIST,
205 L"Software\\Microsoft\\Multimedia\\Sound Mapper",
206 L"Record");
207 }
208
209 if (pGlobalData->bMIDIOutChanged)
210 {
211 UpdateRegistryString(hwnd,
212 IDC_DEVICE_MIDI_LIST,
213 L"Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia\\MIDIMap",
214 L"szPname");
215 }
216 }
217
218 static UINT
GetDevNum(HWND hControl,DWORD Id)219 GetDevNum(HWND hControl, DWORD Id)
220 {
221 int iCurSel;
222 UINT DevNum;
223
224 iCurSel = SendMessageW(hControl, CB_GETCURSEL, 0, 0);
225
226 if (iCurSel == CB_ERR)
227 return 0;
228
229 DevNum = (UINT)SendMessageW(hControl, CB_GETITEMDATA, iCurSel, 0);
230 if (DevNum == (UINT) CB_ERR)
231 return 0;
232
233 if (mixerGetID((HMIXEROBJ)IntToPtr(DevNum), &DevNum, Id) != MMSYSERR_NOERROR)
234 return 0;
235
236 return DevNum;
237 }
238
239 /* Audio property page dialog callback */
240 INT_PTR CALLBACK
AudioDlgProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)241 AudioDlgProc(HWND hwndDlg,
242 UINT uMsg,
243 WPARAM wParam,
244 LPARAM lParam)
245 {
246 PGLOBAL_DATA pGlobalData;
247
248 pGlobalData = (PGLOBAL_DATA)GetWindowLongPtrW(hwndDlg, DWLP_USER);
249
250 switch (uMsg)
251 {
252 case WM_INITDIALOG:
253 {
254 UINT NumWavOut = waveOutGetNumDevs();
255
256 pGlobalData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLOBAL_DATA));
257 SetWindowLongPtrW(hwndDlg, DWLP_USER, (LONG_PTR)pGlobalData);
258
259 if (!pGlobalData)
260 break;
261
262 InitAudioDlg(hwndDlg, pGlobalData);
263
264 if (!NumWavOut)
265 {
266 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVICE_PLAY_LIST), FALSE);
267 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVICE_REC_LIST), FALSE);
268 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVICE_MIDI_LIST), FALSE);
269 EnableWindow(GetDlgItem(hwndDlg, IDC_DEFAULT_DEV_CHECKBOX), FALSE);
270 EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME1_BTN), FALSE);
271 EnableWindow(GetDlgItem(hwndDlg, IDC_ADV2_BTN), FALSE);
272 EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME2_BTN), FALSE);
273 EnableWindow(GetDlgItem(hwndDlg, IDC_ADV1_BTN), FALSE);
274 EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME3_BTN), FALSE);
275 EnableWindow(GetDlgItem(hwndDlg, IDC_ADV3_BTN), FALSE);
276 }
277
278 if (pGlobalData->bNoAudioOut)
279 {
280 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVICE_PLAY_LIST), FALSE);
281 EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME1_BTN), FALSE);
282 EnableWindow(GetDlgItem(hwndDlg, IDC_ADV2_BTN), FALSE);
283 }
284
285 if (pGlobalData->bNoAudioIn)
286 {
287 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVICE_REC_LIST), FALSE);
288 EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME2_BTN), FALSE);
289 EnableWindow(GetDlgItem(hwndDlg, IDC_ADV1_BTN), FALSE);
290 }
291
292 if (pGlobalData->bNoMIDIOut)
293 {
294 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVICE_MIDI_LIST), FALSE);
295 EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME3_BTN), FALSE);
296 EnableWindow(GetDlgItem(hwndDlg, IDC_ADV3_BTN), FALSE);
297 }
298 }
299 break;
300
301 case WM_COMMAND:
302 {
303 STARTUPINFOW si;
304 PROCESS_INFORMATION pi;
305 WCHAR szPath[MAX_PATH];
306
307 if (!pGlobalData)
308 break;
309
310 switch (LOWORD(wParam))
311 {
312 case IDC_VOLUME1_BTN:
313 {
314 StringCchPrintfW(szPath, _countof(szPath), L"sndvol32.exe -d %d",
315 GetDevNum(GetDlgItem(hwndDlg, IDC_DEVICE_PLAY_LIST), MIXER_OBJECTF_WAVEOUT));
316
317 ZeroMemory(&si, sizeof(si));
318 si.cb = sizeof(si);
319 si.dwFlags = STARTF_USESHOWWINDOW;
320 si.wShowWindow = SW_SHOW;
321
322 if (CreateProcessW(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
323 {
324 CloseHandle(pi.hProcess);
325 CloseHandle(pi.hThread);
326 }
327 }
328 break;
329
330 case IDC_ADV2_BTN:
331 {
332
333 }
334 break;
335
336 case IDC_VOLUME2_BTN:
337 {
338 StringCchPrintfW(szPath, _countof(szPath), L"sndvol32.exe -r -d %d",
339 GetDevNum(GetDlgItem(hwndDlg, IDC_DEVICE_REC_LIST), MIXER_OBJECTF_WAVEIN));
340
341 ZeroMemory(&si, sizeof(si));
342 si.cb = sizeof(si);
343 si.dwFlags = STARTF_USESHOWWINDOW;
344 si.wShowWindow = SW_SHOW;
345
346 if (CreateProcessW(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
347 {
348 CloseHandle(pi.hProcess);
349 CloseHandle(pi.hThread);
350 }
351 }
352 break;
353
354 case IDC_ADV1_BTN:
355 {
356
357 }
358 break;
359
360 case IDC_VOLUME3_BTN:
361 {
362 StringCchPrintfW(szPath, _countof(szPath), L"sndvol32.exe -d %d",
363 GetDevNum(GetDlgItem(hwndDlg, IDC_DEVICE_MIDI_LIST), MIXER_OBJECTF_MIDIOUT));
364
365 ZeroMemory(&si, sizeof(si));
366 si.cb = sizeof(si);
367 si.dwFlags = STARTF_USESHOWWINDOW;
368 si.wShowWindow = SW_SHOW;
369
370 if (CreateProcessW(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
371 {
372 CloseHandle(pi.hProcess);
373 CloseHandle(pi.hThread);
374 }
375 }
376 break;
377
378 case IDC_ADV3_BTN:
379 {
380
381 }
382 break;
383
384 case IDC_DEVICE_PLAY_LIST:
385 {
386 if (HIWORD(wParam) == CBN_SELCHANGE)
387 {
388 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
389 pGlobalData->bAudioOutChanged = TRUE;
390 }
391 }
392 break;
393
394 case IDC_DEVICE_REC_LIST:
395 {
396 if (HIWORD(wParam) == CBN_SELCHANGE)
397 {
398 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
399 pGlobalData->bAudioInChanged = TRUE;
400 }
401 }
402
403 case IDC_DEVICE_MIDI_LIST:
404 {
405 if (HIWORD(wParam) == CBN_SELCHANGE)
406 {
407 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
408 pGlobalData->bMIDIOutChanged = TRUE;
409 }
410 }
411 break;
412 }
413 }
414 break;
415
416 case WM_DESTROY:
417 if (!pGlobalData)
418 break;
419
420 HeapFree(GetProcessHeap(), 0, pGlobalData);
421 break;
422
423 case WM_NOTIFY:
424 if (!pGlobalData)
425 break;
426
427 if (((LPNMHDR)lParam)->code == (UINT)PSN_APPLY)
428 {
429 SaveAudioDlg(hwndDlg, pGlobalData);
430 }
431 return TRUE;
432 }
433
434 return FALSE;
435 }
436