xref: /reactos/dll/cpl/mmsys/audio.c (revision 3da25b73)
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