1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Configuration of network devices 4 * FILE: dll/directx/dsound_new/directsound.c 5 * PURPOSE: Handles IDirectSound interface 6 * 7 * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org) 8 */ 9 10 #include "precomp.h" 11 12 typedef struct 13 { 14 IDirectSound8Vtbl *lpVtbl; 15 LONG ref; 16 GUID DeviceGUID; 17 BOOL bInitialized; 18 BOOL bDirectSound8; 19 DWORD dwLevel; 20 LPFILTERINFO Filter; 21 LPDIRECTSOUNDBUFFER8 PrimaryBuffer; 22 23 24 }CDirectSoundImpl, *LPCDirectSoundImpl; 25 26 HRESULT 27 WINAPI 28 IDirectSound8_fnQueryInterface( 29 LPDIRECTSOUND8 iface, 30 REFIID riid, 31 LPVOID * ppobj) 32 { 33 LPOLESTR pStr; 34 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl); 35 36 if ((IsEqualIID(riid, &IID_IDirectSound) && This->bDirectSound8 == FALSE) || 37 (IsEqualIID(riid, &IID_IDirectSound8) && This->bDirectSound8 != FALSE) || 38 (IsEqualIID(riid, &IID_IUnknown))) 39 { 40 *ppobj = (LPVOID)&This->lpVtbl; 41 InterlockedIncrement(&This->ref); 42 return S_OK; 43 } 44 45 if (SUCCEEDED(StringFromIID(riid, &pStr))) 46 { 47 DPRINT("No Interface for class %s\n", pStr); 48 CoTaskMemFree(pStr); 49 } 50 return E_NOINTERFACE; 51 } 52 53 ULONG 54 WINAPI 55 IDirectSound8_fnAddRef( 56 LPDIRECTSOUND8 iface) 57 { 58 ULONG ref; 59 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl); 60 61 ref = InterlockedIncrement(&This->ref); 62 63 return ref; 64 } 65 66 ULONG 67 WINAPI 68 IDirectSound8_fnRelease( 69 LPDIRECTSOUND8 iface) 70 { 71 ULONG ref; 72 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl); 73 74 ref = InterlockedDecrement(&(This->ref)); 75 76 if (!ref) 77 { 78 HeapFree(GetProcessHeap(), 0, This); 79 } 80 81 return ref; 82 } 83 84 HRESULT 85 WINAPI 86 IDirectSound8_fnCreateSoundBuffer( 87 LPDIRECTSOUND8 iface, 88 LPCDSBUFFERDESC lpcDSBufferDesc, 89 LPLPDIRECTSOUNDBUFFER lplpDirectSoundBuffer, 90 IUnknown FAR* pUnkOuter) 91 { 92 HRESULT hResult; 93 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl); 94 95 if (!This->bInitialized) 96 { 97 /* object not yet initialized */ 98 return DSERR_UNINITIALIZED; 99 } 100 101 if (!lpcDSBufferDesc || !lplpDirectSoundBuffer || pUnkOuter != NULL) 102 { 103 DPRINT("Invalid parameter %p %p %p\n", lpcDSBufferDesc, lplpDirectSoundBuffer, pUnkOuter); 104 return DSERR_INVALIDPARAM; 105 } 106 107 /* check buffer description */ 108 if ((lpcDSBufferDesc->dwSize != sizeof(DSBUFFERDESC) && lpcDSBufferDesc->dwSize != sizeof(DSBUFFERDESC1)) || lpcDSBufferDesc->dwReserved != 0) 109 { 110 DPRINT("Invalid buffer description size %u expected %u dwReserved %u\n", lpcDSBufferDesc->dwSize, sizeof(DSBUFFERDESC1), lpcDSBufferDesc->dwReserved); 111 return DSERR_INVALIDPARAM; 112 } 113 114 DPRINT("This %p dwFlags %x dwBufferBytes %u lpwfxFormat %p dwSize %u\n", This, lpcDSBufferDesc->dwFlags, lpcDSBufferDesc->dwBufferBytes, lpcDSBufferDesc->lpwfxFormat, lpcDSBufferDesc->dwSize); 115 116 if (lpcDSBufferDesc->dwFlags & DSBCAPS_PRIMARYBUFFER) 117 { 118 if (lpcDSBufferDesc->lpwfxFormat != NULL) 119 { 120 /* format must be null for primary sound buffer */ 121 return DSERR_INVALIDPARAM; 122 } 123 124 if (lpcDSBufferDesc->dwBufferBytes != 0) 125 { 126 /* buffer size must be zero for primary sound buffer */ 127 return DSERR_INVALIDPARAM; 128 } 129 130 if (This->PrimaryBuffer) 131 { 132 /* primary buffer already exists */ 133 IDirectSoundBuffer8_AddRef(This->PrimaryBuffer); 134 *lplpDirectSoundBuffer = (LPDIRECTSOUNDBUFFER)This->PrimaryBuffer; 135 return S_OK; 136 } 137 138 hResult = NewPrimarySoundBuffer((LPLPDIRECTSOUNDBUFFER8)lplpDirectSoundBuffer, This->Filter, This->dwLevel, lpcDSBufferDesc->dwFlags); 139 if (SUCCEEDED(hResult)) 140 { 141 /* store primary buffer */ 142 This->PrimaryBuffer = (LPDIRECTSOUNDBUFFER8)*lplpDirectSoundBuffer; 143 } 144 return hResult; 145 } 146 else 147 { 148 if (lpcDSBufferDesc->lpwfxFormat == NULL) 149 { 150 /* format must not be null */ 151 return DSERR_INVALIDPARAM; 152 } 153 154 if (lpcDSBufferDesc->dwBufferBytes < DSBSIZE_MIN || lpcDSBufferDesc->dwBufferBytes > DSBSIZE_MAX) 155 { 156 /* buffer size must be within bounds for secondary sound buffer*/ 157 return DSERR_INVALIDPARAM; 158 } 159 160 if (!This->PrimaryBuffer) 161 { 162 hResult = NewPrimarySoundBuffer((LPLPDIRECTSOUNDBUFFER8)lplpDirectSoundBuffer, This->Filter, This->dwLevel, lpcDSBufferDesc->dwFlags); 163 if (SUCCEEDED(hResult)) 164 { 165 /* store primary buffer */ 166 This->PrimaryBuffer = (LPDIRECTSOUNDBUFFER8)*lplpDirectSoundBuffer; 167 } 168 else 169 { 170 DPRINT("Failed to create primary buffer with %x\n", hResult); 171 return hResult; 172 } 173 174 } 175 176 ASSERT(This->PrimaryBuffer); 177 178 DPRINT("This %p wFormatTag %x nChannels %u nSamplesPerSec %u nAvgBytesPerSec %u NBlockAlign %u wBitsPerSample %u cbSize %u\n", 179 This, lpcDSBufferDesc->lpwfxFormat->wFormatTag, lpcDSBufferDesc->lpwfxFormat->nChannels, lpcDSBufferDesc->lpwfxFormat->nSamplesPerSec, lpcDSBufferDesc->lpwfxFormat->nAvgBytesPerSec, lpcDSBufferDesc->lpwfxFormat->nBlockAlign, lpcDSBufferDesc->lpwfxFormat->wBitsPerSample, lpcDSBufferDesc->lpwfxFormat->cbSize); 180 181 hResult = NewSecondarySoundBuffer((LPLPDIRECTSOUNDBUFFER8)lplpDirectSoundBuffer, This->Filter, This->dwLevel, lpcDSBufferDesc, This->PrimaryBuffer); 182 return hResult; 183 } 184 } 185 186 HRESULT 187 WINAPI 188 IDirectSound8_fnGetCaps( 189 LPDIRECTSOUND8 iface, 190 LPDSCAPS lpDSCaps) 191 { 192 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl); 193 194 if (!This->bInitialized) 195 { 196 /* object not yet initialized */ 197 return DSERR_UNINITIALIZED; 198 } 199 200 if (!lpDSCaps) 201 { 202 /* object not yet initialized */ 203 return DSERR_INVALIDPARAM; 204 } 205 206 if (lpDSCaps->dwSize != sizeof(DSCAPS)) 207 { 208 /* object not yet initialized */ 209 return DSERR_INVALIDPARAM; 210 } 211 212 UNIMPLEMENTED; 213 return DSERR_GENERIC; 214 } 215 216 HRESULT 217 WINAPI 218 IDirectSound8_fnDuplicateSoundBuffer( 219 LPDIRECTSOUND8 iface, 220 LPDIRECTSOUNDBUFFER lpDsbOriginal, 221 LPLPDIRECTSOUNDBUFFER lplpDsbDuplicate) 222 { 223 UNIMPLEMENTED; 224 return DSERR_OUTOFMEMORY; 225 } 226 227 HRESULT 228 WINAPI 229 IDirectSound8_fnSetCooperativeLevel( 230 LPDIRECTSOUND8 iface, 231 HWND hwnd, 232 DWORD dwLevel) 233 { 234 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl); 235 236 if (!This->bInitialized) 237 { 238 /* object not yet initialized */ 239 return DSERR_UNINITIALIZED; 240 } 241 242 /* store cooperation level */ 243 This->dwLevel = dwLevel; 244 return DS_OK; 245 } 246 247 HRESULT 248 WINAPI 249 IDirectSound8_fnCompact( 250 LPDIRECTSOUND8 iface) 251 { 252 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl); 253 254 if (!This->bInitialized) 255 { 256 /* object not yet initialized */ 257 return DSERR_UNINITIALIZED; 258 } 259 260 if (This->dwLevel != DSSCL_PRIORITY) 261 { 262 /* needs priority level */ 263 return DSERR_PRIOLEVELNEEDED; 264 } 265 266 /* done */ 267 return DS_OK; 268 } 269 270 HRESULT 271 WINAPI 272 IDirectSound8_fnGetSpeakerConfig( 273 LPDIRECTSOUND8 iface, 274 LPDWORD pdwSpeakerConfig) 275 { 276 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl); 277 278 if (!This->bInitialized) 279 { 280 /* object not yet initialized */ 281 return DSERR_UNINITIALIZED; 282 } 283 284 285 UNIMPLEMENTED; 286 return DSERR_INVALIDPARAM; 287 } 288 289 HRESULT 290 WINAPI 291 IDirectSound8_fnSetSpeakerConfig( 292 LPDIRECTSOUND8 iface, 293 DWORD dwSpeakerConfig) 294 { 295 UNIMPLEMENTED; 296 return DSERR_INVALIDPARAM; 297 } 298 299 300 HRESULT 301 WINAPI 302 IDirectSound8_fnInitialize( 303 LPDIRECTSOUND8 iface, 304 LPCGUID pcGuidDevice) 305 { 306 GUID DeviceGuid; 307 LPOLESTR pGuidStr; 308 HRESULT hr; 309 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl); 310 311 if (!RootInfo) 312 { 313 EnumAudioDeviceInterfaces(&RootInfo); 314 } 315 316 /* sanity check */ 317 ASSERT(RootInfo); 318 319 if (This->bInitialized) 320 { 321 /* object has already been initialized */ 322 return DSERR_ALREADYINITIALIZED; 323 } 324 325 /* fixme mutual exclusion */ 326 327 if (pcGuidDevice == NULL || IsEqualGUID(pcGuidDevice, &GUID_NULL)) 328 { 329 /* use default playback device id */ 330 pcGuidDevice = &DSDEVID_DefaultPlayback; 331 } 332 333 if (IsEqualIID(pcGuidDevice, &DSDEVID_DefaultCapture) || IsEqualIID(pcGuidDevice, &DSDEVID_DefaultVoiceCapture)) 334 { 335 /* this has to be a winetest */ 336 return DSERR_NODRIVER; 337 } 338 339 /* now verify the guid */ 340 if (GetDeviceID(pcGuidDevice, &DeviceGuid) != DS_OK) 341 { 342 if (SUCCEEDED(StringFromIID(pcGuidDevice, &pGuidStr))) 343 { 344 DPRINT("IDirectSound8_fnInitialize: Unknown GUID %ws\n", pGuidStr); 345 CoTaskMemFree(pGuidStr); 346 } 347 return DSERR_INVALIDPARAM; 348 } 349 350 hr = FindDeviceByGuid(&DeviceGuid, &This->Filter); 351 352 if (SUCCEEDED(hr)) 353 { 354 This->bInitialized = TRUE; 355 return DS_OK; 356 } 357 358 DPRINT("Failed to find device\n"); 359 return DSERR_INVALIDPARAM; 360 } 361 362 HRESULT 363 WINAPI 364 IDirectSound8_fnVerifyCertification( 365 LPDIRECTSOUND8 iface, 366 LPDWORD pdwCertified) 367 { 368 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl); 369 370 if (!This->bInitialized) 371 { 372 /* object not yet initialized */ 373 return DSERR_UNINITIALIZED; 374 } 375 376 UNIMPLEMENTED; 377 return DS_CERTIFIED; 378 } 379 380 static IDirectSound8Vtbl vt_DirectSound8 = 381 { 382 /* IUnknown methods */ 383 IDirectSound8_fnQueryInterface, 384 IDirectSound8_fnAddRef, 385 IDirectSound8_fnRelease, 386 /* IDirectSound methods */ 387 IDirectSound8_fnCreateSoundBuffer, 388 IDirectSound8_fnGetCaps, 389 IDirectSound8_fnDuplicateSoundBuffer, 390 IDirectSound8_fnSetCooperativeLevel, 391 IDirectSound8_fnCompact, 392 IDirectSound8_fnGetSpeakerConfig, 393 IDirectSound8_fnSetSpeakerConfig, 394 IDirectSound8_fnInitialize, 395 /* IDirectSound8 methods */ 396 IDirectSound8_fnVerifyCertification 397 }; 398 399 HRESULT 400 InternalDirectSoundCreate( 401 LPCGUID lpcGUID, 402 LPDIRECTSOUND8 *ppDS, 403 IUnknown *pUnkOuter, 404 BOOL bDirectSound8) 405 { 406 LPCDirectSoundImpl This; 407 HRESULT hr; 408 409 if (!ppDS || pUnkOuter != NULL) 410 { 411 /* invalid parameter passed */ 412 return DSERR_INVALIDPARAM; 413 } 414 415 /* allocate CDirectSoundImpl struct */ 416 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CDirectSoundImpl)); 417 if (!This) 418 { 419 /* not enough memory */ 420 return DSERR_OUTOFMEMORY; 421 } 422 423 /* initialize IDirectSound object */ 424 This->ref = 1; 425 This->bDirectSound8 = bDirectSound8; 426 This->lpVtbl = &vt_DirectSound8; 427 428 429 /* initialize direct sound interface */ 430 hr = IDirectSound8_Initialize((LPDIRECTSOUND8)&This->lpVtbl, lpcGUID); 431 432 /* check for success */ 433 if (!SUCCEEDED(hr)) 434 { 435 /* failed */ 436 DPRINT("Failed to initialize DirectSound object with %x\n", hr); 437 IDirectSound8_Release((LPDIRECTSOUND8)&This->lpVtbl); 438 return hr; 439 } 440 441 /* store result */ 442 *ppDS = (LPDIRECTSOUND8)&This->lpVtbl; 443 DPRINT("DirectSound object %p\n", *ppDS); 444 return DS_OK; 445 } 446 447 HRESULT 448 CALLBACK 449 NewDirectSound( 450 IUnknown* pUnkOuter, 451 REFIID riid, 452 LPVOID* ppvObject) 453 { 454 LPOLESTR pStr; 455 LPCDirectSoundImpl This; 456 457 /* check param */ 458 if (!ppvObject) 459 { 460 /* invalid param */ 461 return E_INVALIDARG; 462 } 463 464 /* check requested interface */ 465 if (!IsEqualIID(riid, &IID_IUnknown) && !IsEqualIID(riid, &IID_IDirectSound) && !IsEqualIID(riid, &IID_IDirectSound8)) 466 { 467 *ppvObject = 0; 468 StringFromIID(riid, &pStr); 469 DPRINT("KsPropertySet does not support Interface %ws\n", pStr); 470 CoTaskMemFree(pStr); 471 return E_NOINTERFACE; 472 } 473 474 /* allocate CDirectSoundCaptureImpl struct */ 475 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CDirectSoundImpl)); 476 if (!This) 477 { 478 /* not enough memory */ 479 return DSERR_OUTOFMEMORY; 480 } 481 482 /* initialize object */ 483 This->ref = 1; 484 This->lpVtbl = &vt_DirectSound8; 485 This->bInitialized = FALSE; 486 *ppvObject = (LPVOID)&This->lpVtbl; 487 488 return S_OK; 489 } 490 491 492 HRESULT 493 WINAPI 494 DirectSoundCreate( 495 LPCGUID lpcGUID, 496 LPDIRECTSOUND *ppDS, 497 IUnknown *pUnkOuter) 498 { 499 return InternalDirectSoundCreate(lpcGUID, (LPDIRECTSOUND8*)ppDS, pUnkOuter, FALSE); 500 } 501 502 HRESULT 503 WINAPI 504 DirectSoundCreate8( 505 LPCGUID lpcGUID, 506 LPDIRECTSOUND8 *ppDS, 507 IUnknown *pUnkOuter) 508 { 509 return InternalDirectSoundCreate(lpcGUID, ppDS, pUnkOuter, TRUE); 510 } 511