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 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 165 UpdateRegistryString(HWND hwnd, INT ctrl, LPWSTR key, LPWSTR 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 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 = 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 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