xref: /reactos/dll/cpl/mmsys/audio.c (revision 8a978a17)
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
26 InitAudioDlg(HWND hwnd, PGLOBAL_DATA pGlobalData)
27 {
28     WAVEOUTCAPSW waveOutputPaps;
29     WAVEINCAPS waveInputPaps;
30     MIDIOUTCAPS midiOutCaps;
31     TCHAR szNoDevices[256];
32     UINT DevsNum;
33     UINT uIndex;
34     HWND hCB;
35     LRESULT Res;
36 
37     LoadString(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 = SendMessage(hCB, CB_ADDSTRING, 0, (LPARAM)szNoDevices);
46         SendMessage(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[MAX_PATH-1] = L'\0';
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                 SendMessage(hCB, CB_SETITEMDATA, Res, (LPARAM) uIndex);
73                 if (!wcsicmp(waveOutputPaps.szPname, DefaultDevice))
74                     DefaultIndex = Res;
75             }
76         }
77         SendMessage(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 = SendMessage(hCB, CB_ADDSTRING, 0, (LPARAM)szNoDevices);
87         SendMessage(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[MAX_PATH-1] = L'\0';
101             RegCloseKey(hKey);
102         }
103 
104 
105         for (uIndex = 0; uIndex < DevsNum; uIndex++)
106         {
107             if (waveInGetDevCaps(uIndex, &waveInputPaps, sizeof(waveInputPaps)))
108                 continue;
109 
110             Res = SendMessage(hCB, CB_ADDSTRING, 0, (LPARAM) waveInputPaps.szPname);
111 
112             if (CB_ERR != Res)
113             {
114                 SendMessage(hCB, CB_SETITEMDATA, Res, (LPARAM) uIndex);
115                 if (!wcsicmp(waveInputPaps.szPname, DefaultDevice))
116                     DefaultIndex = Res;
117             }
118         }
119         SendMessage(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 = SendMessage(hCB, CB_ADDSTRING, 0, (LPARAM)szNoDevices);
129         SendMessage(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[MAX_PATH-1] = L'\0';
143             RegCloseKey(hKey);
144         }
145 
146         for (uIndex = 0; uIndex < DevsNum; uIndex++)
147         {
148             if (midiOutGetDevCaps(uIndex, &midiOutCaps, sizeof(midiOutCaps)))
149                 continue;
150 
151             Res = SendMessage(hCB, CB_ADDSTRING, 0, (LPARAM) midiOutCaps.szPname);
152 
153             if (CB_ERR != Res)
154             {
155                 SendMessage(hCB, CB_SETITEMDATA, Res, (LPARAM) uIndex);
156                 if (!wcsicmp(midiOutCaps.szPname, DefaultDevice))
157                     DefaultIndex = Res;
158             }
159         }
160         SendMessage(hCB, CB_SETCURSEL, (WPARAM) DefaultIndex, 0);
161     }
162 }
163 
164 VOID
165 UpdateRegistryString(HWND hwnd, INT ctrl, LPWSTR key, LPWSTR value)
166 {
167     HWND hwndCombo = GetDlgItem(hwnd, ctrl);
168     INT CurSel = SendMessage(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
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
219 GetDevNum(HWND hControl, DWORD Id)
220 {
221     int iCurSel;
222     UINT DevNum;
223 
224     iCurSel = SendMessage(hControl, CB_GETCURSEL, 0, 0);
225 
226     if (iCurSel == CB_ERR)
227         return 0;
228 
229     DevNum = (UINT) SendMessage(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
241 AudioDlgProc(HWND hwndDlg,
242              UINT uMsg,
243              WPARAM wParam,
244              LPARAM lParam)
245 {
246     PGLOBAL_DATA pGlobalData;
247 
248     pGlobalData = (PGLOBAL_DATA)GetWindowLongPtr(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             SetWindowLongPtr(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             STARTUPINFO 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                     wsprintf(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                     CreateProcess(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
323                 }
324                 break;
325 
326                 case IDC_ADV2_BTN:
327                 {
328 
329                 }
330                 break;
331 
332                 case IDC_VOLUME2_BTN:
333                 {
334                     wsprintf(szPath, L"sndvol32.exe -r -d %d",
335                              GetDevNum(GetDlgItem(hwndDlg, IDC_DEVICE_REC_LIST), MIXER_OBJECTF_WAVEIN));
336 
337                     ZeroMemory(&si, sizeof(si));
338                     si.cb = sizeof(si);
339                     si.dwFlags = STARTF_USESHOWWINDOW;
340                     si.wShowWindow = SW_SHOW;
341 
342                     CreateProcess(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
343                 }
344                 break;
345 
346                 case IDC_ADV1_BTN:
347                 {
348 
349                 }
350                 break;
351 
352                 case IDC_VOLUME3_BTN:
353                 {
354                     wsprintf(szPath, L"sndvol32.exe -d %d",
355                              GetDevNum(GetDlgItem(hwndDlg, IDC_DEVICE_MIDI_LIST), MIXER_OBJECTF_MIDIOUT));
356 
357                     ZeroMemory(&si, sizeof(si));
358                     si.cb = sizeof(si);
359                     si.dwFlags = STARTF_USESHOWWINDOW;
360                     si.wShowWindow = SW_SHOW;
361 
362                     CreateProcess(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
363                 }
364                 break;
365 
366                 case IDC_ADV3_BTN:
367                 {
368 
369                 }
370                 break;
371 
372                 case IDC_DEVICE_PLAY_LIST:
373                 {
374                     if (HIWORD(wParam) == CBN_SELCHANGE)
375                     {
376                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
377                         pGlobalData->bAudioOutChanged = TRUE;
378                     }
379                 }
380                 break;
381 
382                 case IDC_DEVICE_REC_LIST:
383                 {
384                     if (HIWORD(wParam) == CBN_SELCHANGE)
385                     {
386                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
387                         pGlobalData->bAudioInChanged = TRUE;
388                     }
389                 }
390 
391                 case IDC_DEVICE_MIDI_LIST:
392                 {
393                     if (HIWORD(wParam) == CBN_SELCHANGE)
394                     {
395                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
396                         pGlobalData->bMIDIOutChanged = TRUE;
397                     }
398                 }
399                 break;
400             }
401         }
402         break;
403 
404         case WM_DESTROY:
405             if (!pGlobalData)
406                 break;
407 
408             HeapFree(GetProcessHeap(), 0, pGlobalData);
409             break;
410 
411         case WM_NOTIFY:
412             if (!pGlobalData)
413                 break;
414 
415             if (((LPNMHDR)lParam)->code == (UINT)PSN_APPLY)
416             {
417                 SaveAudioDlg(hwndDlg, pGlobalData);
418             }
419             return TRUE;
420     }
421 
422     return FALSE;
423 }
424