/*************************************************************************** * DirectSoundEnumerateW [DSOUND.3] * * Enumerate all DirectSound drivers installed in the system * * PARAMS * lpDSEnumCallback [I] Address of callback function. * lpContext [I] Address of user defined context passed to callback function. * * RETURNS * Success: DS_OK * Failure: DSERR_INVALIDPARAM */ HRESULT WINAPI DirectSoundEnumerateW( LPDSENUMCALLBACKW lpDSEnumCallback, LPVOID lpContext ) { unsigned devs, wod; DSDRIVERDESC desc; GUID guid; int err; WCHAR wDesc[MAXPNAMELEN]; WCHAR wName[MAXPNAMELEN]; TRACE("lpDSEnumCallback = %p, lpContext = %p\n", lpDSEnumCallback, lpContext); if (lpDSEnumCallback == NULL) { WARN("invalid parameter: lpDSEnumCallback == NULL\n"); return DSERR_INVALIDPARAM; } setup_dsound_options(); devs = waveOutGetNumDevs(); if (devs > 0) { if (GetDeviceID(&DSDEVID_DefaultPlayback, &guid) == DS_OK) { static const WCHAR empty[] = { 0 }; for (wod = 0; wod < devs; ++wod) { if (IsEqualGUID( &guid, &DSOUND_renderer_guids[wod] ) ) { err = mmErr(waveOutMessage(UlongToHandle(wod),DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,ds_hw_accel)); if (err == DS_OK) { TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n", "Primary Sound Driver",desc.szDrvname,lpContext); MultiByteToWideChar( CP_ACP, 0, "Primary Sound Driver", -1, wDesc, sizeof(wDesc)/sizeof(WCHAR) ); if (lpDSEnumCallback(NULL, wDesc, empty, lpContext) == FALSE) return DS_OK; } } } } } for (wod = 0; wod < devs; ++wod) { err = mmErr(waveOutMessage(UlongToHandle(wod),DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,ds_hw_accel)); if (err == DS_OK) { TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n", debugstr_guid(&DSOUND_renderer_guids[wod]),desc.szDesc,desc.szDrvname,lpContext); MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, wDesc, sizeof(wDesc)/sizeof(WCHAR) ); wDesc[(sizeof(wDesc)/sizeof(WCHAR)) - 1] = '\0'; MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, wName, sizeof(wName)/sizeof(WCHAR) ); wName[(sizeof(wName)/sizeof(WCHAR)) - 1] = '\0'; if (lpDSEnumCallback(&DSOUND_renderer_guids[wod], wDesc, wName, lpContext) == FALSE) return DS_OK; } } return DS_OK; }
HRESULT DSOUND_PrimaryPlay(DirectSoundDevice *device) { HRESULT err = DS_OK; TRACE("(%p)\n", device); err = mmErr(waveOutRestart(device->hwo)); if (err != DS_OK) WARN("waveOutRestart failed\n"); return err; }
HRESULT DSOUND_PrimaryPlay(DirectSoundDevice *device) { HRESULT err = DS_OK; TRACE("(%p)\n", device); if (device->hwbuf) { err = IDsDriverBuffer_Play(device->hwbuf, 0, 0, DSBPLAY_LOOPING); if (err != DS_OK) WARN("IDsDriverBuffer_Play failed\n"); } else { err = mmErr(waveOutRestart(device->hwo)); if (err != DS_OK) WARN("waveOutRestart failed\n"); } return err; }
HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device) { HRESULT err = DS_OK; TRACE("(%p)\n", device); /* don't call the wave system with the lock set */ LeaveCriticalSection(&(device->mixlock)); err = mmErr(waveOutPause(device->hwo)); EnterCriticalSection(&(device->mixlock)); if (err != DS_OK) WARN("waveOutPause failed\n"); return err; }
HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave) { HRESULT hres = DS_OK; TRACE("(%p, %d)\n", device, forcewave); waveOutClose(device->hwo); device->drvdesc.dwFlags = 0; hres = mmErr(waveOutOpen(&(device->hwo), device->drvdesc.dnDevNode, device->pwfx, (DWORD_PTR)DSOUND_callback, (DWORD_PTR)device, CALLBACK_FUNCTION | WAVE_MAPPED)); if (FAILED(hres)) { WARN("waveOutOpen failed: %08x\n", hres); return hres; } return hres; }
HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device) { HRESULT err = DS_OK; TRACE("(%p)\n", device); if (device->hwbuf) { err = IDsDriverBuffer_Stop(device->hwbuf); if (err == DSERR_BUFFERLOST) { DSOUND_PrimaryClose(device); err = DSOUND_ReopenDevice(device, FALSE); if (FAILED(err)) ERR("DSOUND_ReopenDevice failed\n"); else { err = DSOUND_PrimaryOpen(device); if (FAILED(err)) WARN("DSOUND_PrimaryOpen failed\n"); } } else if (err != DS_OK) { WARN("IDsDriverBuffer_Stop failed\n"); } } else { /* don't call the wave system with the lock set */ LeaveCriticalSection(&(device->mixlock)); /* **** */ err = mmErr(waveOutPause(device->hwo)); /* **** */ EnterCriticalSection(&(device->mixlock)); if (err != DS_OK) WARN("waveOutPause failed\n"); } return err; }
HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave) { HRESULT hres = DS_OK; TRACE("(%p, %d)\n", device, forcewave); if (device->driver) { IDsDriver_Close(device->driver); if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN) waveOutClose(device->hwo); IDsDriver_Release(device->driver); device->driver = NULL; device->buffer = NULL; device->hwo = 0; } else if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN) waveOutClose(device->hwo); /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */ if (ds_hw_accel != DS_HW_ACCEL_EMULATION && !forcewave) waveOutMessage((HWAVEOUT)device->drvdesc.dnDevNode, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&device->driver, 0); /* Get driver description */ if (device->driver) { DWORD wod = device->drvdesc.dnDevNode; hres = IDsDriver_GetDriverDesc(device->driver,&(device->drvdesc)); device->drvdesc.dnDevNode = wod; if (FAILED(hres)) { WARN("IDsDriver_GetDriverDesc failed: %08x\n", hres); IDsDriver_Release(device->driver); device->driver = NULL; } } /* if no DirectSound interface available, use WINMM API instead */ if (!device->driver) device->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT; if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN) { DWORD flags = CALLBACK_FUNCTION; if (device->driver) flags |= WAVE_DIRECTSOUND; hres = mmErr(waveOutOpen(&(device->hwo), device->drvdesc.dnDevNode, device->pwfx, (DWORD_PTR)DSOUND_callback, (DWORD_PTR)device, flags)); if (FAILED(hres)) { WARN("waveOutOpen failed\n"); if (device->driver) { IDsDriver_Release(device->driver); device->driver = NULL; } return hres; } } if (device->driver) hres = IDsDriver_Open(device->driver); return hres; }
static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device) { DWORD buflen; HRESULT err = DS_OK; TRACE("(%p)\n", device); /* on original windows, the buffer it set to a fixed size, no matter what the settings are. on windows this size is always fixed (tested on win-xp) */ if (!device->buflen) device->buflen = ds_hel_buflen; buflen = device->buflen; buflen -= buflen % device->pwfx->nBlockAlign; device->buflen = buflen; if (device->driver) { err = IDsDriver_CreateSoundBuffer(device->driver,device->pwfx, DSBCAPS_PRIMARYBUFFER,0, &(device->buflen),&(device->buffer), (LPVOID*)&(device->hwbuf)); if (err != DS_OK) { WARN("IDsDriver_CreateSoundBuffer failed (%08x), falling back to waveout\n", err); err = DSOUND_ReopenDevice(device, TRUE); if (FAILED(err)) { WARN("Falling back to waveout failed too! Giving up\n"); return err; } } if (device->hwbuf) IDsDriverBuffer_SetVolumePan(device->hwbuf, &device->volpan); DSOUND_RecalcPrimary(device); device->prebuf = ds_snd_queue_max; if (device->helfrags < ds_snd_queue_min) { WARN("Too little sound buffer to be effective (%d/%d) falling back to waveout\n", device->buflen, ds_snd_queue_min * device->fraglen); device->buflen = buflen; IDsDriverBuffer_Release(device->hwbuf); device->hwbuf = NULL; err = DSOUND_ReopenDevice(device, TRUE); if (FAILED(err)) { WARN("Falling back to waveout failed too! Giving up\n"); return err; } } else if (device->helfrags < ds_snd_queue_max) device->prebuf = device->helfrags; } device->mix_buffer_len = DSOUND_bufpos_to_mixpos(device, device->buflen); device->mix_buffer = HeapAlloc(GetProcessHeap(), 0, device->mix_buffer_len); if (!device->mix_buffer) { if (device->hwbuf) IDsDriverBuffer_Release(device->hwbuf); device->hwbuf = NULL; return DSERR_OUTOFMEMORY; } if (device->state == STATE_PLAYING) device->state = STATE_STARTING; else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED; /* are we using waveOut stuff? */ if (!device->driver) { LPBYTE newbuf; LPWAVEHDR headers = NULL; DWORD overshot; unsigned int c; /* Start in pause mode, to allow buffers to get filled */ waveOutPause(device->hwo); TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer); /* reallocate emulated primary buffer */ if (device->buffer) newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer, buflen); else newbuf = HeapAlloc(GetProcessHeap(),0, buflen); if (!newbuf) { ERR("failed to allocate primary buffer\n"); return DSERR_OUTOFMEMORY; /* but the old buffer might still exist and must be re-prepared */ } DSOUND_RecalcPrimary(device); if (device->pwave) headers = HeapReAlloc(GetProcessHeap(),0,device->pwave, device->helfrags * sizeof(WAVEHDR)); else headers = HeapAlloc(GetProcessHeap(),0,device->helfrags * sizeof(WAVEHDR)); if (!headers) { ERR("failed to allocate wave headers\n"); HeapFree(GetProcessHeap(), 0, newbuf); DSOUND_RecalcPrimary(device); return DSERR_OUTOFMEMORY; } device->buffer = newbuf; device->pwave = headers; /* prepare fragment headers */ for (c=0; c<device->helfrags; c++) { device->pwave[c].lpData = (char*)device->buffer + c*device->fraglen; device->pwave[c].dwBufferLength = device->fraglen; device->pwave[c].dwUser = (DWORD_PTR)device; device->pwave[c].dwFlags = 0; device->pwave[c].dwLoops = 0; err = mmErr(waveOutPrepareHeader(device->hwo,&device->pwave[c],sizeof(WAVEHDR))); if (err != DS_OK) { while (c--) waveOutUnprepareHeader(device->hwo,&device->pwave[c],sizeof(WAVEHDR)); break; } } overshot = device->buflen % device->fraglen; /* sanity */ if(overshot) { overshot -= overshot % device->pwfx->nBlockAlign; device->pwave[device->helfrags - 1].dwBufferLength += overshot; } TRACE("fraglen=%d, overshot=%d\n", device->fraglen, overshot); } device->mixfunction = mixfunctions[device->pwfx->wBitsPerSample/8 - 1]; device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1]; FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0); FillMemory(device->mix_buffer, device->mix_buffer_len, 0); device->pwplay = device->pwqueue = device->playpos = device->mixpos = 0; return err; }
static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device) { DWORD buflen; HRESULT err = DS_OK; LPBYTE newbuf; LPWAVEHDR headers = NULL; DWORD overshot; unsigned int c; TRACE("(%p)\n", device); /* on original windows, the buffer it set to a fixed size, no matter what the settings are. on windows this size is always fixed (tested on win-xp) */ if (!device->buflen) device->buflen = ds_hel_buflen; buflen = device->buflen; buflen -= buflen % device->pwfx->nBlockAlign; device->buflen = buflen; device->mix_buffer_len = DSOUND_bufpos_to_mixpos(device, device->buflen); device->mix_buffer = HeapAlloc(GetProcessHeap(), 0, device->mix_buffer_len); if (!device->mix_buffer) return DSERR_OUTOFMEMORY; if (device->state == STATE_PLAYING) device->state = STATE_STARTING; else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED; /* Start in pause mode, to allow buffers to get filled */ waveOutPause(device->hwo); TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer); /* reallocate emulated primary buffer */ if (device->buffer) newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer, buflen); else newbuf = HeapAlloc(GetProcessHeap(),0, buflen); if (!newbuf) { ERR("failed to allocate primary buffer\n"); return DSERR_OUTOFMEMORY; /* but the old buffer might still exist and must be re-prepared */ } DSOUND_RecalcPrimary(device); if (device->pwave) headers = HeapReAlloc(GetProcessHeap(),0,device->pwave, device->helfrags * sizeof(WAVEHDR)); else headers = HeapAlloc(GetProcessHeap(),0,device->helfrags * sizeof(WAVEHDR)); if (!headers) { ERR("failed to allocate wave headers\n"); HeapFree(GetProcessHeap(), 0, newbuf); DSOUND_RecalcPrimary(device); return DSERR_OUTOFMEMORY; } device->buffer = newbuf; device->pwave = headers; /* prepare fragment headers */ for (c=0; c<device->helfrags; c++) { device->pwave[c].lpData = (char*)device->buffer + c*device->fraglen; device->pwave[c].dwBufferLength = device->fraglen; device->pwave[c].dwUser = (DWORD_PTR)device; device->pwave[c].dwFlags = 0; device->pwave[c].dwLoops = 0; err = mmErr(waveOutPrepareHeader(device->hwo,&device->pwave[c],sizeof(WAVEHDR))); if (err != DS_OK) { while (c--) waveOutUnprepareHeader(device->hwo,&device->pwave[c],sizeof(WAVEHDR)); break; } } overshot = device->buflen % device->fraglen; /* sanity */ if(overshot) { overshot -= overshot % device->pwfx->nBlockAlign; device->pwave[device->helfrags - 1].dwBufferLength += overshot; } TRACE("fraglen=%d, overshot=%d\n", device->fraglen, overshot); device->mixfunction = mixfunctions[device->pwfx->wBitsPerSample/8 - 1]; device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1]; FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0); FillMemory(device->mix_buffer, device->mix_buffer_len, 0); device->pwplay = device->pwqueue = device->playpos = device->mixpos = 0; return err; }