dsound: Reimplement rendering devices on mmdevapi.
This commit is contained in:
parent
4b8a296365
commit
e786998daf
|
@ -1,6 +1,6 @@
|
|||
MODULE = dsound.dll
|
||||
IMPORTLIB = dsound
|
||||
IMPORTS = dxguid uuid winmm ole32 advapi32
|
||||
IMPORTS = dxguid uuid winmm ole32 advapi32 user32
|
||||
|
||||
C_SRCS = \
|
||||
buffer.c \
|
||||
|
|
|
@ -23,12 +23,12 @@
|
|||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define COBJMACROS
|
||||
#define NONAMELESSSTRUCT
|
||||
#define NONAMELESSUNION
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winuser.h"
|
||||
#include "mmsystem.h"
|
||||
#include "winternl.h"
|
||||
#include "mmddk.h"
|
||||
#include "wingdi.h"
|
||||
|
@ -1248,6 +1248,10 @@ ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
|
|||
RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);
|
||||
RtlReleaseResource(&(device->buffer_list_lock));
|
||||
|
||||
EnterCriticalSection(&DSOUND_renderers_lock);
|
||||
list_remove(&device->entry);
|
||||
LeaveCriticalSection(&DSOUND_renderers_lock);
|
||||
|
||||
/* It is allowed to release this object even when buffers are playing */
|
||||
if (device->buffers) {
|
||||
WARN("%d secondary buffers not released\n", device->nrofbuffers);
|
||||
|
@ -1264,9 +1268,14 @@ ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
|
|||
if (hr != DS_OK)
|
||||
WARN("DSOUND_PrimaryDestroy failed\n");
|
||||
|
||||
waveOutClose(device->hwo);
|
||||
|
||||
DSOUND_renderer[device->drvdesc.dnDevNode] = NULL;
|
||||
if(device->client)
|
||||
IAudioClient_Release(device->client);
|
||||
if(device->render)
|
||||
IAudioRenderClient_Release(device->render);
|
||||
if(device->clock)
|
||||
IAudioClock_Release(device->clock);
|
||||
if(device->volume)
|
||||
IAudioStreamVolume_Release(device->volume);
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, device->tmp_buffer);
|
||||
HeapFree(GetProcessHeap(), 0, device->mix_buffer);
|
||||
|
@ -1334,14 +1343,57 @@ HRESULT DirectSoundDevice_GetCaps(
|
|||
return DS_OK;
|
||||
}
|
||||
|
||||
static BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate,
|
||||
DWORD depth, WORD channels)
|
||||
{
|
||||
WAVEFORMATEX fmt, *junk;
|
||||
HRESULT hr;
|
||||
|
||||
fmt.wFormatTag = WAVE_FORMAT_PCM;
|
||||
fmt.nChannels = channels;
|
||||
fmt.nSamplesPerSec = rate;
|
||||
fmt.wBitsPerSample = depth;
|
||||
fmt.nBlockAlign = (channels * depth) / 8;
|
||||
fmt.nAvgBytesPerSec = rate * fmt.nBlockAlign;
|
||||
fmt.cbSize = 0;
|
||||
|
||||
hr = IAudioClient_IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED, &fmt, &junk);
|
||||
if(SUCCEEDED(hr))
|
||||
CoTaskMemFree(junk);
|
||||
|
||||
return hr == S_OK;
|
||||
}
|
||||
|
||||
static UINT DSOUND_create_timer(LPTIMECALLBACK cb, DWORD_PTR user)
|
||||
{
|
||||
UINT triggertime = DS_TIME_DEL, res = DS_TIME_RES, id;
|
||||
TIMECAPS time;
|
||||
|
||||
timeGetDevCaps(&time, sizeof(TIMECAPS));
|
||||
TRACE("Minimum timer resolution: %u, max timer: %u\n", time.wPeriodMin, time.wPeriodMax);
|
||||
if (triggertime < time.wPeriodMin)
|
||||
triggertime = time.wPeriodMin;
|
||||
if (res < time.wPeriodMin)
|
||||
res = time.wPeriodMin;
|
||||
if (timeBeginPeriod(res) == TIMERR_NOCANDO)
|
||||
WARN("Could not set minimum resolution, don't expect sound\n");
|
||||
id = timeSetEvent(triggertime, res, cb, user, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
|
||||
if (!id)
|
||||
{
|
||||
WARN("Timer not created! Retrying without TIME_KILL_SYNCHRONOUS\n");
|
||||
id = timeSetEvent(triggertime, res, cb, user, TIME_PERIODIC);
|
||||
if (!id)
|
||||
ERR("Could not create timer, sound playback will not occur\n");
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
|
||||
{
|
||||
HRESULT hr = DS_OK;
|
||||
unsigned wod, wodn;
|
||||
BOOLEAN found = FALSE;
|
||||
GUID devGUID;
|
||||
DirectSoundDevice * device = *ppDevice;
|
||||
WAVEOUTCAPSA woc;
|
||||
DirectSoundDevice *device;
|
||||
IMMDevice *mmdevice;
|
||||
|
||||
TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
|
||||
|
||||
|
@ -1354,130 +1406,97 @@ HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcG
|
|||
if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
|
||||
lpcGUID = &DSDEVID_DefaultPlayback;
|
||||
|
||||
if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultCapture) ||
|
||||
IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoiceCapture))
|
||||
return DSERR_NODRIVER;
|
||||
|
||||
if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
|
||||
WARN("invalid parameter: lpcGUID\n");
|
||||
return DSERR_INVALIDPARAM;
|
||||
}
|
||||
|
||||
/* Enumerate WINMM audio devices and find the one we want */
|
||||
wodn = waveOutGetNumDevs();
|
||||
if (!wodn) {
|
||||
WARN("no driver\n");
|
||||
return DSERR_NODRIVER;
|
||||
}
|
||||
hr = get_mmdevice(eRender, &devGUID, &mmdevice);
|
||||
if(FAILED(hr))
|
||||
return hr;
|
||||
|
||||
for (wod=0; wod<wodn; wod++) {
|
||||
if (IsEqualGUID( &devGUID, &DSOUND_renderer_guids[wod])) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
EnterCriticalSection(&DSOUND_renderers_lock);
|
||||
|
||||
if (found == FALSE) {
|
||||
WARN("No device found matching given ID!\n");
|
||||
return DSERR_NODRIVER;
|
||||
}
|
||||
|
||||
if (DSOUND_renderer[wod]) {
|
||||
if (IsEqualGUID(&devGUID, &DSOUND_renderer[wod]->guid)) {
|
||||
device = DSOUND_renderer[wod];
|
||||
LIST_FOR_EACH_ENTRY(device, &DSOUND_renderers, DirectSoundDevice, entry){
|
||||
if(IsEqualGUID(&device->guid, &devGUID)){
|
||||
IMMDevice_Release(mmdevice);
|
||||
DirectSoundDevice_AddRef(device);
|
||||
*ppDevice = device;
|
||||
LeaveCriticalSection(&DSOUND_renderers_lock);
|
||||
return DS_OK;
|
||||
} else {
|
||||
ERR("device GUID doesn't match\n");
|
||||
hr = DSERR_GENERIC;
|
||||
return hr;
|
||||
}
|
||||
} else {
|
||||
hr = DirectSoundDevice_Create(&device);
|
||||
if (hr != DS_OK) {
|
||||
WARN("DirectSoundDevice_Create failed\n");
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
*ppDevice = device;
|
||||
hr = DirectSoundDevice_Create(&device);
|
||||
if(FAILED(hr)){
|
||||
WARN("DirectSoundDevice_Create failed\n");
|
||||
IMMDevice_Release(mmdevice);
|
||||
LeaveCriticalSection(&DSOUND_renderers_lock);
|
||||
return hr;
|
||||
}
|
||||
|
||||
device->mmdevice = mmdevice;
|
||||
device->guid = devGUID;
|
||||
|
||||
device->drvdesc.dnDevNode = wod;
|
||||
hr = DSOUND_ReopenDevice(device, FALSE);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, device);
|
||||
LeaveCriticalSection(&DSOUND_renderers_lock);
|
||||
IMMDevice_Release(mmdevice);
|
||||
WARN("DSOUND_ReopenDevice failed: %08x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = mmErr(waveOutGetDevCapsA(device->drvdesc.dnDevNode, &woc, sizeof(woc)));
|
||||
if (hr != DS_OK) {
|
||||
WARN("waveOutGetDevCaps failed\n");
|
||||
return hr;
|
||||
}
|
||||
ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
|
||||
if ((woc.dwFormats & WAVE_FORMAT_1M08) ||
|
||||
(woc.dwFormats & WAVE_FORMAT_2M08) ||
|
||||
(woc.dwFormats & WAVE_FORMAT_4M08) ||
|
||||
(woc.dwFormats & WAVE_FORMAT_48M08) ||
|
||||
(woc.dwFormats & WAVE_FORMAT_96M08)) {
|
||||
device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
|
||||
device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
|
||||
}
|
||||
if ((woc.dwFormats & WAVE_FORMAT_1M16) ||
|
||||
(woc.dwFormats & WAVE_FORMAT_2M16) ||
|
||||
(woc.dwFormats & WAVE_FORMAT_4M16) ||
|
||||
(woc.dwFormats & WAVE_FORMAT_48M16) ||
|
||||
(woc.dwFormats & WAVE_FORMAT_96M16)) {
|
||||
device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
|
||||
device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
|
||||
}
|
||||
if ((woc.dwFormats & WAVE_FORMAT_1S08) ||
|
||||
(woc.dwFormats & WAVE_FORMAT_2S08) ||
|
||||
(woc.dwFormats & WAVE_FORMAT_4S08) ||
|
||||
(woc.dwFormats & WAVE_FORMAT_48S08) ||
|
||||
(woc.dwFormats & WAVE_FORMAT_96S08)) {
|
||||
device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
|
||||
device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
|
||||
}
|
||||
if ((woc.dwFormats & WAVE_FORMAT_1S16) ||
|
||||
(woc.dwFormats & WAVE_FORMAT_2S16) ||
|
||||
(woc.dwFormats & WAVE_FORMAT_4S16) ||
|
||||
(woc.dwFormats & WAVE_FORMAT_48S16) ||
|
||||
(woc.dwFormats & WAVE_FORMAT_96S16)) {
|
||||
device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
|
||||
device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
|
||||
}
|
||||
|
||||
if(ds_emuldriver)
|
||||
device->drvcaps.dwFlags |= DSCAPS_EMULDRIVER;
|
||||
if(DSOUND_check_supported(device->client, 11025, 8, 1) ||
|
||||
DSOUND_check_supported(device->client, 22050, 8, 1) ||
|
||||
DSOUND_check_supported(device->client, 44100, 8, 1) ||
|
||||
DSOUND_check_supported(device->client, 48000, 8, 1) ||
|
||||
DSOUND_check_supported(device->client, 96000, 8, 1))
|
||||
device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYMONO;
|
||||
|
||||
if(DSOUND_check_supported(device->client, 11025, 16, 1) ||
|
||||
DSOUND_check_supported(device->client, 22050, 16, 1) ||
|
||||
DSOUND_check_supported(device->client, 44100, 16, 1) ||
|
||||
DSOUND_check_supported(device->client, 48000, 16, 1) ||
|
||||
DSOUND_check_supported(device->client, 96000, 16, 1))
|
||||
device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYMONO;
|
||||
|
||||
if(DSOUND_check_supported(device->client, 11025, 8, 2) ||
|
||||
DSOUND_check_supported(device->client, 22050, 8, 2) ||
|
||||
DSOUND_check_supported(device->client, 44100, 8, 2) ||
|
||||
DSOUND_check_supported(device->client, 48000, 8, 2) ||
|
||||
DSOUND_check_supported(device->client, 96000, 8, 2))
|
||||
device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYSTEREO;
|
||||
|
||||
if(DSOUND_check_supported(device->client, 11025, 16, 2) ||
|
||||
DSOUND_check_supported(device->client, 22050, 16, 2) ||
|
||||
DSOUND_check_supported(device->client, 44100, 16, 2) ||
|
||||
DSOUND_check_supported(device->client, 48000, 16, 2) ||
|
||||
DSOUND_check_supported(device->client, 96000, 16, 2))
|
||||
device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO;
|
||||
|
||||
device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
|
||||
device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
|
||||
|
||||
ZeroMemory(&device->volpan, sizeof(device->volpan));
|
||||
|
||||
hr = DSOUND_PrimaryCreate(device);
|
||||
if (hr == DS_OK) {
|
||||
UINT triggertime = DS_TIME_DEL, res = DS_TIME_RES, id;
|
||||
TIMECAPS time;
|
||||
if (hr == DS_OK)
|
||||
device->timerID = DSOUND_create_timer(DSOUND_timer, (DWORD_PTR)device);
|
||||
else
|
||||
WARN("DSOUND_PrimaryCreate failed: %08x\n", hr);
|
||||
|
||||
DSOUND_renderer[device->drvdesc.dnDevNode] = device;
|
||||
timeGetDevCaps(&time, sizeof(TIMECAPS));
|
||||
TRACE("Minimum timer resolution: %u, max timer: %u\n", time.wPeriodMin, time.wPeriodMax);
|
||||
if (triggertime < time.wPeriodMin)
|
||||
triggertime = time.wPeriodMin;
|
||||
if (res < time.wPeriodMin)
|
||||
res = time.wPeriodMin;
|
||||
if (timeBeginPeriod(res) == TIMERR_NOCANDO)
|
||||
WARN("Could not set minimum resolution, don't expect sound\n");
|
||||
id = timeSetEvent(triggertime, res, DSOUND_timer, (DWORD_PTR)device, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
|
||||
if (!id)
|
||||
{
|
||||
WARN("Timer not created! Retrying without TIME_KILL_SYNCHRONOUS\n");
|
||||
id = timeSetEvent(triggertime, res, DSOUND_timer, (DWORD_PTR)device, TIME_PERIODIC);
|
||||
if (!id) ERR("Could not create timer, sound playback will not occur\n");
|
||||
}
|
||||
DSOUND_renderer[device->drvdesc.dnDevNode]->timerID = id;
|
||||
} else {
|
||||
WARN("DSOUND_PrimaryCreate failed\n");
|
||||
}
|
||||
*ppDevice = device;
|
||||
list_add_tail(&DSOUND_renderers, &device->entry);
|
||||
|
||||
LeaveCriticalSection(&DSOUND_renderers_lock);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
|
|
@ -50,17 +50,31 @@
|
|||
#include "dsconf.h"
|
||||
#include "ks.h"
|
||||
#include "rpcproxy.h"
|
||||
#include "rpc.h"
|
||||
#include "rpcndr.h"
|
||||
#include "unknwn.h"
|
||||
#include "oleidl.h"
|
||||
#include "shobjidl.h"
|
||||
|
||||
#include "initguid.h"
|
||||
#include "ksmedia.h"
|
||||
#include "propkey.h"
|
||||
#include "devpkey.h"
|
||||
|
||||
#include "dsound_private.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dsound);
|
||||
|
||||
DirectSoundDevice* DSOUND_renderer[MAXWAVEDRIVERS];
|
||||
struct list DSOUND_renderers = LIST_INIT(DSOUND_renderers);
|
||||
CRITICAL_SECTION DSOUND_renderers_lock;
|
||||
|
||||
GUID DSOUND_renderer_guids[MAXWAVEDRIVERS];
|
||||
GUID DSOUND_capture_guids[MAXWAVEDRIVERS];
|
||||
|
||||
static IMMDeviceEnumerator *g_devenum;
|
||||
static CRITICAL_SECTION g_devenum_lock;
|
||||
static HANDLE g_devenum_thread;
|
||||
|
||||
HRESULT mmErr(UINT err)
|
||||
{
|
||||
switch(err) {
|
||||
|
@ -196,6 +210,117 @@ static const char * get_device_id(LPCGUID pGuid)
|
|||
return debugstr_guid(pGuid);
|
||||
}
|
||||
|
||||
/* The MMDeviceEnumerator object has to be created & destroyed
|
||||
* from the same thread. */
|
||||
static DWORD WINAPI devenum_thread_proc(void *arg)
|
||||
{
|
||||
HANDLE evt = arg;
|
||||
HRESULT hr;
|
||||
MSG msg;
|
||||
|
||||
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
if(FAILED(hr)){
|
||||
ERR("CoInitializeEx failed: %08x\n", hr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL,
|
||||
CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&g_devenum);
|
||||
if(FAILED(hr)){
|
||||
ERR("CoCreateInstance failed: %08x\n", hr);
|
||||
CoUninitialize();
|
||||
return 1;
|
||||
}
|
||||
|
||||
SetEvent(evt);
|
||||
|
||||
PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
|
||||
|
||||
while(GetMessageW(&msg, NULL, 0, 0)){
|
||||
if(msg.hwnd)
|
||||
DispatchMessageW(&msg);
|
||||
else
|
||||
ERR("Unknown message: %04x\n", msg.message);
|
||||
}
|
||||
|
||||
IMMDeviceEnumerator_Release(g_devenum);
|
||||
g_devenum = NULL;
|
||||
CoUninitialize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static IMMDeviceEnumerator *get_mmdevenum(void)
|
||||
{
|
||||
HANDLE events[2];
|
||||
DWORD wait;
|
||||
|
||||
EnterCriticalSection(&g_devenum_lock);
|
||||
|
||||
if(g_devenum){
|
||||
LeaveCriticalSection(&g_devenum_lock);
|
||||
return g_devenum;
|
||||
}
|
||||
|
||||
events[0] = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
|
||||
g_devenum_thread = CreateThread(NULL, 0, devenum_thread_proc,
|
||||
events[0], 0, NULL);
|
||||
if(!g_devenum_thread){
|
||||
LeaveCriticalSection(&g_devenum_lock);
|
||||
CloseHandle(events[0]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
events[1] = g_devenum_thread;
|
||||
wait = WaitForMultipleObjects(2, events, FALSE, INFINITE);
|
||||
CloseHandle(events[0]);
|
||||
if(wait != WAIT_OBJECT_0){
|
||||
if(wait == 1 + WAIT_OBJECT_0){
|
||||
CloseHandle(g_devenum_thread);
|
||||
g_devenum_thread = NULL;
|
||||
}
|
||||
LeaveCriticalSection(&g_devenum_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&g_devenum_lock);
|
||||
|
||||
return g_devenum;
|
||||
}
|
||||
|
||||
static HRESULT get_mmdevice_guid(IMMDevice *device, IPropertyStore *ps,
|
||||
GUID *guid)
|
||||
{
|
||||
PROPVARIANT pv;
|
||||
HRESULT hr;
|
||||
|
||||
if(!ps){
|
||||
hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps);
|
||||
if(FAILED(hr)){
|
||||
WARN("OpenPropertyStore failed: %08x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
}else
|
||||
IPropertyStore_AddRef(ps);
|
||||
|
||||
PropVariantInit(&pv);
|
||||
|
||||
hr = IPropertyStore_GetValue(ps, &PKEY_AudioEndpoint_GUID, &pv);
|
||||
if(FAILED(hr)){
|
||||
IPropertyStore_Release(ps);
|
||||
WARN("GetValue(GUID) failed: %08x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
CLSIDFromString(pv.u.pwszVal, guid);
|
||||
|
||||
PropVariantClear(&pv);
|
||||
IPropertyStore_Release(ps);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* GetDeviceID [DSOUND.9]
|
||||
*
|
||||
|
@ -218,34 +343,51 @@ static const char * get_device_id(LPCGUID pGuid)
|
|||
*/
|
||||
HRESULT WINAPI GetDeviceID(LPCGUID pGuidSrc, LPGUID pGuidDest)
|
||||
{
|
||||
IMMDeviceEnumerator *devenum;
|
||||
EDataFlow flow = (EDataFlow)-1;
|
||||
ERole role = (ERole)-1;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%s,%p)\n", get_device_id(pGuidSrc),pGuidDest);
|
||||
|
||||
if ( pGuidSrc == NULL) {
|
||||
WARN("invalid parameter: pGuidSrc == NULL\n");
|
||||
return DSERR_INVALIDPARAM;
|
||||
if(!pGuidSrc || !pGuidDest)
|
||||
return DSERR_INVALIDPARAM;
|
||||
|
||||
devenum = get_mmdevenum();
|
||||
if(!devenum)
|
||||
return DSERR_GENERIC;
|
||||
|
||||
if(IsEqualGUID(&DSDEVID_DefaultPlayback, pGuidSrc)){
|
||||
role = eMultimedia;
|
||||
flow = eRender;
|
||||
}else if(IsEqualGUID(&DSDEVID_DefaultVoicePlayback, pGuidSrc)){
|
||||
role = eCommunications;
|
||||
flow = eRender;
|
||||
}else if(IsEqualGUID(&DSDEVID_DefaultCapture, pGuidSrc)){
|
||||
role = eMultimedia;
|
||||
flow = eCapture;
|
||||
}else if(IsEqualGUID(&DSDEVID_DefaultVoiceCapture, pGuidSrc)){
|
||||
role = eCommunications;
|
||||
flow = eCapture;
|
||||
}
|
||||
|
||||
if ( pGuidDest == NULL ) {
|
||||
WARN("invalid parameter: pGuidDest == NULL\n");
|
||||
return DSERR_INVALIDPARAM;
|
||||
}
|
||||
if(role != (ERole)-1 && flow != (EDataFlow)-1){
|
||||
IMMDevice *device;
|
||||
|
||||
if ( IsEqualGUID( &DSDEVID_DefaultPlayback, pGuidSrc ) ||
|
||||
IsEqualGUID( &DSDEVID_DefaultVoicePlayback, pGuidSrc ) ) {
|
||||
*pGuidDest = DSOUND_renderer_guids[ds_default_playback];
|
||||
TRACE("returns %s\n", get_device_id(pGuidDest));
|
||||
return DS_OK;
|
||||
}
|
||||
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum,
|
||||
flow, role, &device);
|
||||
if(FAILED(hr)){
|
||||
WARN("GetDefaultAudioEndpoint failed: %08x\n", hr);
|
||||
return DSERR_NODRIVER;
|
||||
}
|
||||
|
||||
if ( IsEqualGUID( &DSDEVID_DefaultCapture, pGuidSrc ) ||
|
||||
IsEqualGUID( &DSDEVID_DefaultVoiceCapture, pGuidSrc ) ) {
|
||||
*pGuidDest = DSOUND_capture_guids[ds_default_capture];
|
||||
TRACE("returns %s\n", get_device_id(pGuidDest));
|
||||
return DS_OK;
|
||||
hr = get_mmdevice_guid(device, NULL, pGuidDest);
|
||||
IMMDevice_Release(device);
|
||||
|
||||
return (hr == S_OK) ? DS_OK : hr;
|
||||
}
|
||||
|
||||
*pGuidDest = *pGuidSrc;
|
||||
TRACE("returns %s\n", get_device_id(pGuidDest));
|
||||
|
||||
return DS_OK;
|
||||
}
|
||||
|
@ -297,6 +439,141 @@ HRESULT WINAPI DirectSoundEnumerateA(
|
|||
return DirectSoundEnumerateW(a_to_w_callback, &context);
|
||||
}
|
||||
|
||||
HRESULT get_mmdevice(EDataFlow flow, const GUID *tgt, IMMDevice **device)
|
||||
{
|
||||
IMMDeviceEnumerator *devenum;
|
||||
IMMDeviceCollection *coll;
|
||||
UINT count, i;
|
||||
HRESULT hr;
|
||||
|
||||
devenum = get_mmdevenum();
|
||||
if(!devenum)
|
||||
return DSERR_GENERIC;
|
||||
|
||||
hr = IMMDeviceEnumerator_EnumAudioEndpoints(devenum, flow,
|
||||
DEVICE_STATE_ACTIVE, &coll);
|
||||
if(FAILED(hr)){
|
||||
WARN("EnumAudioEndpoints failed: %08x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = IMMDeviceCollection_GetCount(coll, &count);
|
||||
if(FAILED(hr)){
|
||||
IMMDeviceCollection_Release(coll);
|
||||
WARN("GetCount failed: %08x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
for(i = 0; i < count; ++i){
|
||||
GUID guid;
|
||||
|
||||
hr = IMMDeviceCollection_Item(coll, i, device);
|
||||
if(FAILED(hr))
|
||||
continue;
|
||||
|
||||
hr = get_mmdevice_guid(*device, NULL, &guid);
|
||||
if(FAILED(hr)){
|
||||
IMMDevice_Release(*device);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(IsEqualGUID(&guid, tgt))
|
||||
return DS_OK;
|
||||
|
||||
IMMDevice_Release(*device);
|
||||
}
|
||||
|
||||
WARN("No device with GUID %s found!\n", wine_dbgstr_guid(tgt));
|
||||
|
||||
return DSERR_INVALIDPARAM;
|
||||
}
|
||||
|
||||
static HRESULT enumerate_mmdevices(EDataFlow flow, GUID *guids,
|
||||
LPDSENUMCALLBACKW cb, void *user)
|
||||
{
|
||||
IMMDeviceEnumerator *devenum;
|
||||
IMMDeviceCollection *coll;
|
||||
UINT count, i;
|
||||
BOOL keep_going;
|
||||
HRESULT hr;
|
||||
|
||||
static const WCHAR primary_desc[] = {'P','r','i','m','a','r','y',' ',
|
||||
'S','o','u','n','d',' ','D','r','i','v','e','r',0};
|
||||
static const WCHAR empty_drv[] = {0};
|
||||
static const WCHAR wine_vxd_drv[] = { 'w','i','n','e','m','m','.',
|
||||
'v','x','d', 0 };
|
||||
|
||||
devenum = get_mmdevenum();
|
||||
if(!devenum)
|
||||
return DS_OK;
|
||||
|
||||
hr = IMMDeviceEnumerator_EnumAudioEndpoints(g_devenum, flow,
|
||||
DEVICE_STATE_ACTIVE, &coll);
|
||||
if(FAILED(hr)){
|
||||
WARN("EnumAudioEndpoints failed: %08x\n", hr);
|
||||
return DS_OK;
|
||||
}
|
||||
|
||||
hr = IMMDeviceCollection_GetCount(coll, &count);
|
||||
if(FAILED(hr)){
|
||||
IMMDeviceCollection_Release(coll);
|
||||
WARN("GetCount failed: %08x\n", hr);
|
||||
return DS_OK;
|
||||
}
|
||||
|
||||
if(count == 0)
|
||||
return DS_OK;
|
||||
|
||||
keep_going = cb(NULL, primary_desc, empty_drv, user);
|
||||
|
||||
for(i = 0; keep_going && i < count; ++i){
|
||||
IMMDevice *device;
|
||||
IPropertyStore *ps;
|
||||
PROPVARIANT pv;
|
||||
|
||||
PropVariantInit(&pv);
|
||||
|
||||
hr = IMMDeviceCollection_Item(coll, i, &device);
|
||||
if(FAILED(hr)){
|
||||
WARN("Item failed: %08x\n", hr);
|
||||
continue;
|
||||
}
|
||||
|
||||
hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps);
|
||||
if(FAILED(hr)){
|
||||
IMMDevice_Release(device);
|
||||
WARN("OpenPropertyStore failed: %08x\n", hr);
|
||||
continue;
|
||||
}
|
||||
|
||||
hr = get_mmdevice_guid(device, ps, &guids[i]);
|
||||
if(FAILED(hr)){
|
||||
IPropertyStore_Release(ps);
|
||||
IMMDevice_Release(device);
|
||||
continue;
|
||||
}
|
||||
|
||||
hr = IPropertyStore_GetValue(ps,
|
||||
(const PROPERTYKEY *)&DEVPKEY_Device_FriendlyName, &pv);
|
||||
if(FAILED(hr)){
|
||||
IPropertyStore_Release(ps);
|
||||
IMMDevice_Release(device);
|
||||
WARN("GetValue(FriendlyName) failed: %08x\n", hr);
|
||||
continue;
|
||||
}
|
||||
|
||||
keep_going = cb(&guids[i], pv.u.pwszVal, wine_vxd_drv, user);
|
||||
|
||||
PropVariantClear(&pv);
|
||||
IPropertyStore_Release(ps);
|
||||
IMMDevice_Release(device);
|
||||
}
|
||||
|
||||
IMMDeviceCollection_Release(coll);
|
||||
|
||||
return DS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* DirectSoundEnumerateW [DSOUND.3]
|
||||
*
|
||||
|
@ -314,55 +591,17 @@ HRESULT WINAPI DirectSoundEnumerateW(
|
|||
LPDSENUMCALLBACKW lpDSEnumCallback,
|
||||
LPVOID lpContext )
|
||||
{
|
||||
unsigned devs, wod;
|
||||
GUID guid;
|
||||
int err;
|
||||
WAVEOUTCAPSW caps;
|
||||
|
||||
const static WCHAR winmmW[] = {'w','i','n','m','m','.','d','l','l',0};
|
||||
const static WCHAR primary_driverW[] = {'P','r','i','m','a','r','y',' ',
|
||||
'S','o','u','n','d',' ','D','r','i','v','e','r',0};
|
||||
|
||||
TRACE("lpDSEnumCallback = %p, lpContext = %p\n",
|
||||
lpDSEnumCallback, lpContext);
|
||||
TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext);
|
||||
|
||||
if (lpDSEnumCallback == NULL) {
|
||||
WARN("invalid parameter: lpDSEnumCallback == NULL\n");
|
||||
return DSERR_INVALIDPARAM;
|
||||
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(waveOutGetDevCapsW(wod, &caps, sizeof(caps)));
|
||||
if (err == DS_OK) {
|
||||
TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n",
|
||||
"Primary Sound Driver","",lpContext);
|
||||
if (lpDSEnumCallback(NULL, primary_driverW, empty, lpContext) == FALSE)
|
||||
return DS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (wod = 0; wod < devs; ++wod) {
|
||||
err = mmErr(waveOutGetDevCapsW(wod, &caps, sizeof(caps)));
|
||||
if (err == DS_OK) {
|
||||
TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
|
||||
debugstr_guid(&DSOUND_renderer_guids[wod]),
|
||||
wine_dbgstr_w(caps.szPname),"winmm.dll",lpContext);
|
||||
|
||||
if (lpDSEnumCallback(&DSOUND_renderer_guids[wod], caps.szPname, winmmW, lpContext) == FALSE)
|
||||
return DS_OK;
|
||||
}
|
||||
}
|
||||
return DS_OK;
|
||||
return enumerate_mmdevices(eRender, DSOUND_renderer_guids,
|
||||
lpDSEnumCallback, lpContext);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
|
@ -645,15 +884,15 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
|||
case DLL_PROCESS_ATTACH:
|
||||
TRACE("DLL_PROCESS_ATTACH\n");
|
||||
for (i = 0; i < MAXWAVEDRIVERS; i++) {
|
||||
DSOUND_renderer[i] = NULL;
|
||||
DSOUND_capture[i] = NULL;
|
||||
INIT_GUID(DSOUND_renderer_guids[i], 0xbd6dd71a, 0x3deb, 0x11d1, 0xb1, 0x71, 0x00, 0xc0, 0x4f, 0xc2, 0x00, 0x00 + i);
|
||||
INIT_GUID(DSOUND_capture_guids[i], 0xbd6dd71b, 0x3deb, 0x11d1, 0xb1, 0x71, 0x00, 0xc0, 0x4f, 0xc2, 0x00, 0x00 + i);
|
||||
}
|
||||
instance = hInstDLL;
|
||||
DisableThreadLibraryCalls(hInstDLL);
|
||||
/* Increase refcount on dsound by 1 */
|
||||
GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)hInstDLL, &hInstDLL);
|
||||
InitializeCriticalSection(&DSOUND_renderers_lock);
|
||||
InitializeCriticalSection(&g_devenum_lock);
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
TRACE("DLL_PROCESS_DETACH\n");
|
||||
|
|
|
@ -23,6 +23,11 @@
|
|||
#define DS_TIME_RES 2 /* Resolution of multimedia timer */
|
||||
#define DS_TIME_DEL 10 /* Delay of multimedia timer callback, and duration of HEL fragment */
|
||||
|
||||
#include "wingdi.h"
|
||||
#include "mmdeviceapi.h"
|
||||
#include "audioclient.h"
|
||||
#include "mmsystem.h"
|
||||
|
||||
#include "wine/list.h"
|
||||
|
||||
extern int ds_emuldriver DECLSPEC_HIDDEN;
|
||||
|
@ -132,9 +137,8 @@ struct DirectSoundDevice
|
|||
DSDRIVERCAPS drvcaps;
|
||||
DWORD priolevel;
|
||||
PWAVEFORMATEX pwfx;
|
||||
HWAVEOUT hwo;
|
||||
LPWAVEHDR pwave;
|
||||
UINT timerID, pwplay, pwqueue, prebuf, helfrags;
|
||||
UINT64 last_pos_bytes;
|
||||
DWORD fraglen;
|
||||
LPBYTE buffer;
|
||||
DWORD writelead, buflen, state, playpos, mixpos;
|
||||
|
@ -156,6 +160,14 @@ struct DirectSoundDevice
|
|||
IDirectSound3DListenerImpl* listener;
|
||||
DS3DLISTENER ds3dl;
|
||||
BOOL ds3dl_need_recalc;
|
||||
|
||||
IMMDevice *mmdevice;
|
||||
IAudioClient *client;
|
||||
IAudioClock *clock;
|
||||
IAudioStreamVolume *volume;
|
||||
IAudioRenderClient *render;
|
||||
|
||||
struct list entry;
|
||||
};
|
||||
|
||||
/* reference counted buffer memory for duplicated buffer memory */
|
||||
|
@ -397,7 +409,6 @@ void DSOUND_MixToTemporary(const IDirectSoundBufferImpl *dsb, DWORD writepos, DW
|
|||
DWORD DSOUND_secpos_to_bufpos(const IDirectSoundBufferImpl *dsb, DWORD secpos, DWORD secmixpos, DWORD* overshot) DECLSPEC_HIDDEN;
|
||||
|
||||
void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) DECLSPEC_HIDDEN;
|
||||
void CALLBACK DSOUND_callback(HWAVEOUT hwo, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) DECLSPEC_HIDDEN;
|
||||
|
||||
/* sound3d.c */
|
||||
|
||||
|
@ -416,12 +427,16 @@ HRESULT DSOUND_CaptureCreate8(REFIID riid, LPDIRECTSOUNDCAPTURE8 *ppDSC8) DECLSP
|
|||
|
||||
#define DSOUND_FREQSHIFT (20)
|
||||
|
||||
extern DirectSoundDevice* DSOUND_renderer[MAXWAVEDRIVERS] DECLSPEC_HIDDEN;
|
||||
extern GUID DSOUND_renderer_guids[MAXWAVEDRIVERS] DECLSPEC_HIDDEN;
|
||||
extern CRITICAL_SECTION DSOUND_renderers_lock DECLSPEC_HIDDEN;
|
||||
extern struct list DSOUND_renderers DECLSPEC_HIDDEN;
|
||||
|
||||
extern DirectSoundCaptureDevice * DSOUND_capture[MAXWAVEDRIVERS] DECLSPEC_HIDDEN;
|
||||
|
||||
extern GUID DSOUND_renderer_guids[MAXWAVEDRIVERS] DECLSPEC_HIDDEN;
|
||||
extern GUID DSOUND_capture_guids[MAXWAVEDRIVERS] DECLSPEC_HIDDEN;
|
||||
|
||||
HRESULT mmErr(UINT err) DECLSPEC_HIDDEN;
|
||||
void setup_dsound_options(void) DECLSPEC_HIDDEN;
|
||||
const char * dumpCooperativeLevel(DWORD level) DECLSPEC_HIDDEN;
|
||||
|
||||
HRESULT get_mmdevice(EDataFlow flow, const GUID *tgt, IMMDevice **device) DECLSPEC_HIDDEN;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <stdarg.h>
|
||||
#include <math.h> /* Insomnia - pow() function */
|
||||
|
||||
#define COBJMACROS
|
||||
#define NONAMELESSSTRUCT
|
||||
#define NONAMELESSUNION
|
||||
#include "windef.h"
|
||||
|
@ -742,17 +743,21 @@ static DWORD DSOUND_MixToPrimary(const DirectSoundDevice *device, DWORD writepos
|
|||
|
||||
static void DSOUND_WaveQueue(DirectSoundDevice *device, BOOL force)
|
||||
{
|
||||
DWORD prebuf_frags, wave_writepos, wave_fragpos, i;
|
||||
DWORD prebuf_frames, buf_offs_bytes, wave_fragpos;
|
||||
int prebuf_frags;
|
||||
BYTE *buffer;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p)\n", device);
|
||||
|
||||
/* calculate the current wave frag position */
|
||||
wave_fragpos = (device->pwplay + device->pwqueue) % device->helfrags;
|
||||
|
||||
/* calculate the current wave write position */
|
||||
wave_writepos = wave_fragpos * device->fraglen;
|
||||
buf_offs_bytes = wave_fragpos * device->fraglen;
|
||||
|
||||
TRACE("wave_fragpos = %i, wave_writepos = %i, pwqueue = %i, prebuf = %i\n",
|
||||
wave_fragpos, wave_writepos, device->pwqueue, device->prebuf);
|
||||
TRACE("wave_fragpos = %i, buf_offs_bytes = %i, pwqueue = %i, prebuf = %i\n",
|
||||
wave_fragpos, buf_offs_bytes, device->pwqueue, device->prebuf);
|
||||
|
||||
if (!force)
|
||||
{
|
||||
|
@ -776,23 +781,50 @@ static void DSOUND_WaveQueue(DirectSoundDevice *device, BOOL force)
|
|||
|
||||
TRACE("prebuf_frags = %i\n", prebuf_frags);
|
||||
|
||||
if(!prebuf_frags)
|
||||
return;
|
||||
|
||||
/* adjust queue */
|
||||
device->pwqueue += prebuf_frags;
|
||||
|
||||
/* get out of CS when calling the wave system */
|
||||
LeaveCriticalSection(&(device->mixlock));
|
||||
/* **** */
|
||||
prebuf_frames = ((prebuf_frags + wave_fragpos > device->helfrags) ?
|
||||
(prebuf_frags + wave_fragpos - device->helfrags) :
|
||||
(prebuf_frags)) * device->fraglen / device->pwfx->nBlockAlign;
|
||||
|
||||
/* queue up the new buffers */
|
||||
for(i=0; i<prebuf_frags; i++){
|
||||
TRACE("queueing wave buffer %i\n", wave_fragpos);
|
||||
waveOutWrite(device->hwo, &device->pwave[wave_fragpos], sizeof(WAVEHDR));
|
||||
wave_fragpos++;
|
||||
wave_fragpos %= device->helfrags;
|
||||
hr = IAudioRenderClient_GetBuffer(device->render, prebuf_frames, &buffer);
|
||||
if(FAILED(hr)){
|
||||
WARN("GetBuffer failed: %08x\n", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* **** */
|
||||
EnterCriticalSection(&(device->mixlock));
|
||||
memcpy(buffer, device->buffer + buf_offs_bytes,
|
||||
prebuf_frames * device->pwfx->nBlockAlign);
|
||||
|
||||
hr = IAudioRenderClient_ReleaseBuffer(device->render, prebuf_frames, 0);
|
||||
if(FAILED(hr)){
|
||||
WARN("ReleaseBuffer failed: %08x\n", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check if anything wrapped */
|
||||
prebuf_frags = prebuf_frags + wave_fragpos - device->helfrags;
|
||||
if(prebuf_frags > 0){
|
||||
prebuf_frames = prebuf_frags * device->fraglen / device->pwfx->nBlockAlign;
|
||||
|
||||
hr = IAudioRenderClient_GetBuffer(device->render, prebuf_frames, &buffer);
|
||||
if(FAILED(hr)){
|
||||
WARN("GetBuffer failed: %08x\n", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(buffer, device->buffer, prebuf_frames * device->pwfx->nBlockAlign);
|
||||
|
||||
hr = IAudioRenderClient_ReleaseBuffer(device->render, prebuf_frames, 0);
|
||||
if(FAILED(hr)){
|
||||
WARN("ReleaseBuffer failed: %08x\n", hr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE("queue now = %i\n", device->pwqueue);
|
||||
}
|
||||
|
@ -804,10 +836,39 @@ static void DSOUND_WaveQueue(DirectSoundDevice *device, BOOL force)
|
|||
*/
|
||||
static void DSOUND_PerformMix(DirectSoundDevice *device)
|
||||
{
|
||||
UINT64 clock_pos, clock_freq, pos_bytes;
|
||||
UINT delta_frags;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p)\n", device);
|
||||
|
||||
/* **** */
|
||||
EnterCriticalSection(&(device->mixlock));
|
||||
EnterCriticalSection(&device->mixlock);
|
||||
|
||||
hr = IAudioClock_GetFrequency(device->clock, &clock_freq);
|
||||
if(FAILED(hr)){
|
||||
WARN("GetFrequency failed: %08x\n", hr);
|
||||
LeaveCriticalSection(&device->mixlock);
|
||||
return;
|
||||
}
|
||||
|
||||
hr = IAudioClock_GetPosition(device->clock, &clock_pos, NULL);
|
||||
if(FAILED(hr)){
|
||||
WARN("GetCurrentPadding failed: %08x\n", hr);
|
||||
LeaveCriticalSection(&device->mixlock);
|
||||
return;
|
||||
}
|
||||
|
||||
pos_bytes = (clock_pos / (double)clock_freq) * device->pwfx->nSamplesPerSec *
|
||||
device->pwfx->nBlockAlign;
|
||||
|
||||
delta_frags = (pos_bytes - device->last_pos_bytes) / device->fraglen;
|
||||
if(delta_frags > 0){
|
||||
device->pwplay += delta_frags;
|
||||
device->pwplay %= device->helfrags;
|
||||
device->pwqueue -= delta_frags;
|
||||
device->last_pos_bytes = pos_bytes - (pos_bytes % device->fraglen);
|
||||
}
|
||||
|
||||
if (device->priolevel != DSSCL_WRITEPRIMARY) {
|
||||
BOOL recover = FALSE, all_stopped = FALSE;
|
||||
|
@ -825,7 +886,7 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
|
|||
}
|
||||
|
||||
TRACE("primary playpos=%d, writepos=%d, clrpos=%d, mixpos=%d, buflen=%d\n",
|
||||
playpos,writepos,device->playpos,device->mixpos,device->buflen);
|
||||
playpos,writepos,device->playpos,device->mixpos,device->buflen);
|
||||
assert(device->playpos < device->buflen);
|
||||
|
||||
mixplaypos = DSOUND_bufpos_to_mixpos(device, device->playpos);
|
||||
|
@ -910,7 +971,7 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
|
|||
if (prebuff_left >= device->fraglen){
|
||||
|
||||
/* update the wave queue */
|
||||
DSOUND_WaveQueue(device, FALSE);
|
||||
DSOUND_WaveQueue(device, FALSE);
|
||||
|
||||
/* buffers are full. start playing if applicable */
|
||||
if(device->state == STATE_STARTING){
|
||||
|
@ -948,7 +1009,7 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
|
|||
|
||||
} else {
|
||||
|
||||
DSOUND_WaveQueue(device, TRUE);
|
||||
DSOUND_WaveQueue(device, TRUE);
|
||||
|
||||
/* in the DSSCL_WRITEPRIMARY mode, the app is totally in charge... */
|
||||
if (device->state == STATE_STARTING) {
|
||||
|
@ -978,13 +1039,6 @@ void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
|
|||
TRACE("(%d,%d,0x%lx,0x%lx,0x%lx)\n",timerID,msg,dwUser,dw1,dw2);
|
||||
TRACE("entering at %d\n", start_time);
|
||||
|
||||
if (DSOUND_renderer[device->drvdesc.dnDevNode] != device) {
|
||||
ERR("dsound died without killing us?\n");
|
||||
timeKillEvent(timerID);
|
||||
timeEndPeriod(DS_TIME_RES);
|
||||
return;
|
||||
}
|
||||
|
||||
RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);
|
||||
|
||||
if (device->ref)
|
||||
|
@ -995,37 +1049,3 @@ void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
|
|||
end_time = GetTickCount();
|
||||
TRACE("completed processing at %d, duration = %d\n", end_time, end_time - start_time);
|
||||
}
|
||||
|
||||
void CALLBACK DSOUND_callback(HWAVEOUT hwo, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
|
||||
{
|
||||
DirectSoundDevice * device = (DirectSoundDevice*)dwUser;
|
||||
TRACE("(%p,%x,%lx,%lx,%lx)\n",hwo,msg,dwUser,dw1,dw2);
|
||||
TRACE("entering at %d, msg=%08x(%s)\n", GetTickCount(), msg,
|
||||
msg==MM_WOM_DONE ? "MM_WOM_DONE" : msg==MM_WOM_CLOSE ? "MM_WOM_CLOSE" :
|
||||
msg==MM_WOM_OPEN ? "MM_WOM_OPEN" : "UNKNOWN");
|
||||
|
||||
/* check if packet completed from wave driver */
|
||||
if (msg == MM_WOM_DONE) {
|
||||
|
||||
/* **** */
|
||||
EnterCriticalSection(&(device->mixlock));
|
||||
|
||||
TRACE("done playing primary pos=%d\n", device->pwplay * device->fraglen);
|
||||
|
||||
/* update playpos */
|
||||
device->pwplay++;
|
||||
device->pwplay %= device->helfrags;
|
||||
|
||||
/* sanity */
|
||||
if(device->pwqueue == 0){
|
||||
ERR("Wave queue corrupted!\n");
|
||||
}
|
||||
|
||||
/* update queue */
|
||||
device->pwqueue--;
|
||||
|
||||
LeaveCriticalSection(&(device->mixlock));
|
||||
/* **** */
|
||||
}
|
||||
TRACE("completed\n");
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include <stdarg.h>
|
||||
|
||||
#define COBJMACROS
|
||||
#define NONAMELESSSTRUCT
|
||||
#define NONAMELESSUNION
|
||||
#include "windef.h"
|
||||
|
@ -83,32 +84,86 @@ static void DSOUND_RecalcPrimary(DirectSoundDevice *device)
|
|||
|
||||
HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
|
||||
{
|
||||
HRESULT hres = DS_OK;
|
||||
TRACE("(%p, %d)\n", device, forcewave);
|
||||
HRESULT hres;
|
||||
|
||||
waveOutClose(device->hwo);
|
||||
TRACE("(%p, %d)\n", device, forcewave);
|
||||
|
||||
if(device->client){
|
||||
IAudioClient_Release(device->client);
|
||||
device->client = NULL;
|
||||
}
|
||||
if(device->render){
|
||||
IAudioRenderClient_Release(device->render);
|
||||
device->render = NULL;
|
||||
}
|
||||
if(device->clock){
|
||||
IAudioClock_Release(device->clock);
|
||||
device->clock = NULL;
|
||||
}
|
||||
if(device->volume){
|
||||
IAudioStreamVolume_Release(device->volume);
|
||||
device->volume = NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
hres = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient,
|
||||
CLSCTX_INPROC_SERVER, NULL, (void **)&device->client);
|
||||
if(FAILED(hres)){
|
||||
WARN("Activate failed: %08x\n", hres);
|
||||
return hres;
|
||||
}
|
||||
|
||||
return hres;
|
||||
/* buffer size = 200 * 100000 (100 ns) = 2.0 seconds */
|
||||
hres = IAudioClient_Initialize(device->client,
|
||||
AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST,
|
||||
200 * 100000, 50000, device->pwfx, NULL);
|
||||
if(FAILED(hres)){
|
||||
IAudioClient_Release(device->client);
|
||||
device->client = NULL;
|
||||
WARN("Initialize failed: %08x\n", hres);
|
||||
return hres;
|
||||
}
|
||||
|
||||
hres = IAudioClient_GetService(device->client, &IID_IAudioRenderClient,
|
||||
(void**)&device->render);
|
||||
if(FAILED(hres)){
|
||||
IAudioClient_Release(device->client);
|
||||
device->client = NULL;
|
||||
WARN("GetService failed: %08x\n", hres);
|
||||
return hres;
|
||||
}
|
||||
|
||||
hres = IAudioClient_GetService(device->client, &IID_IAudioClock,
|
||||
(void**)&device->clock);
|
||||
if(FAILED(hres)){
|
||||
IAudioClient_Release(device->client);
|
||||
IAudioRenderClient_Release(device->render);
|
||||
device->client = NULL;
|
||||
device->render = NULL;
|
||||
WARN("GetService failed: %08x\n", hres);
|
||||
return hres;
|
||||
}
|
||||
|
||||
hres = IAudioClient_GetService(device->client, &IID_IAudioStreamVolume,
|
||||
(void**)&device->volume);
|
||||
if(FAILED(hres)){
|
||||
IAudioClient_Release(device->client);
|
||||
IAudioRenderClient_Release(device->render);
|
||||
IAudioClock_Release(device->clock);
|
||||
device->client = NULL;
|
||||
device->render = NULL;
|
||||
device->clock = NULL;
|
||||
WARN("GetService failed: %08x\n", hres);
|
||||
return hres;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
|
||||
{
|
||||
DWORD buflen;
|
||||
HRESULT err = DS_OK;
|
||||
LPBYTE newbuf;
|
||||
LPWAVEHDR headers = NULL;
|
||||
DWORD overshot;
|
||||
unsigned int c;
|
||||
LPBYTE newbuf;
|
||||
|
||||
TRACE("(%p)\n", device);
|
||||
|
||||
|
@ -128,9 +183,6 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
|
|||
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 */
|
||||
|
@ -146,70 +198,33 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
|
|||
}
|
||||
|
||||
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);
|
||||
TRACE("fraglen=%d\n", device->fraglen);
|
||||
|
||||
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;
|
||||
device->last_pos_bytes = device->pwplay = device->pwqueue = device->playpos = device->mixpos = 0;
|
||||
return DS_OK;
|
||||
}
|
||||
|
||||
|
||||
static void DSOUND_PrimaryClose(DirectSoundDevice *device)
|
||||
{
|
||||
unsigned c;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p)\n", device);
|
||||
TRACE("(%p)\n", device);
|
||||
|
||||
/* get out of CS when calling the wave system */
|
||||
LeaveCriticalSection(&(device->mixlock));
|
||||
/* **** */
|
||||
device->pwqueue = (DWORD)-1; /* resetting queues */
|
||||
waveOutReset(device->hwo);
|
||||
for (c=0; c<device->helfrags; c++)
|
||||
waveOutUnprepareHeader(device->hwo, &device->pwave[c], sizeof(WAVEHDR));
|
||||
/* **** */
|
||||
EnterCriticalSection(&(device->mixlock));
|
||||
|
||||
if(device->client){
|
||||
hr = IAudioClient_Stop(device->client);
|
||||
if(FAILED(hr))
|
||||
WARN("Stop failed: %08x\n", hr);
|
||||
}
|
||||
|
||||
/* clear the queue */
|
||||
device->pwqueue = 0;
|
||||
|
@ -240,7 +255,6 @@ HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device)
|
|||
EnterCriticalSection(&(device->mixlock));
|
||||
|
||||
DSOUND_PrimaryClose(device);
|
||||
HeapFree(GetProcessHeap(),0,device->pwave);
|
||||
HeapFree(GetProcessHeap(),0,device->pwfx);
|
||||
device->pwfx=NULL;
|
||||
|
||||
|
@ -252,32 +266,32 @@ HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device)
|
|||
|
||||
HRESULT DSOUND_PrimaryPlay(DirectSoundDevice *device)
|
||||
{
|
||||
HRESULT err = DS_OK;
|
||||
TRACE("(%p)\n", device);
|
||||
HRESULT hr;
|
||||
|
||||
err = mmErr(waveOutRestart(device->hwo));
|
||||
if (err != DS_OK)
|
||||
WARN("waveOutRestart failed\n");
|
||||
TRACE("(%p)\n", device);
|
||||
|
||||
return err;
|
||||
hr = IAudioClient_Start(device->client);
|
||||
if(FAILED(hr)){
|
||||
WARN("Start failed: %08x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
return DS_OK;
|
||||
}
|
||||
|
||||
HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device)
|
||||
{
|
||||
HRESULT err = DS_OK;
|
||||
TRACE("(%p)\n", device);
|
||||
HRESULT hr;
|
||||
|
||||
/* don't call the wave system with the lock set */
|
||||
LeaveCriticalSection(&(device->mixlock));
|
||||
TRACE("(%p)\n", device);
|
||||
|
||||
err = mmErr(waveOutPause(device->hwo));
|
||||
hr = IAudioClient_Stop(device->client);
|
||||
if(FAILED(hr)){
|
||||
WARN("Stop failed: %08x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&(device->mixlock));
|
||||
|
||||
if (err != DS_OK)
|
||||
WARN("waveOutPause failed\n");
|
||||
|
||||
return err;
|
||||
return DS_OK;
|
||||
}
|
||||
|
||||
HRESULT DSOUND_PrimaryGetPosition(DirectSoundDevice *device, LPDWORD playpos, LPDWORD writepos)
|
||||
|
@ -331,15 +345,15 @@ LPWAVEFORMATEX DSOUND_CopyFormat(LPCWAVEFORMATEX wfex)
|
|||
return pwfx;
|
||||
}
|
||||
|
||||
HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex)
|
||||
HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX passed_fmt)
|
||||
{
|
||||
HRESULT err = DSERR_BUFFERLOST;
|
||||
int i;
|
||||
DWORD nSamplesPerSec, bpp, chans;
|
||||
LPWAVEFORMATEX oldpwfx;
|
||||
BOOL forced = device->priolevel == DSSCL_WRITEPRIMARY;
|
||||
WAVEFORMATEX *old_fmt;
|
||||
WAVEFORMATEXTENSIBLE *fmtex;
|
||||
BOOL forced = (device->priolevel == DSSCL_WRITEPRIMARY);
|
||||
|
||||
TRACE("(%p,%p)\n", device, wfex);
|
||||
TRACE("(%p,%p)\n", device, passed_fmt);
|
||||
|
||||
if (device->priolevel == DSSCL_NORMAL) {
|
||||
WARN("failed priority check!\n");
|
||||
|
@ -347,29 +361,26 @@ HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex)
|
|||
}
|
||||
|
||||
/* Let's be pedantic! */
|
||||
if (wfex == NULL) {
|
||||
WARN("invalid parameter: wfex==NULL!\n");
|
||||
if (passed_fmt == NULL) {
|
||||
WARN("invalid parameter: passed_fmt==NULL!\n");
|
||||
return DSERR_INVALIDPARAM;
|
||||
}
|
||||
TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
|
||||
"bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
|
||||
wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
|
||||
wfex->nAvgBytesPerSec, wfex->nBlockAlign,
|
||||
wfex->wBitsPerSample, wfex->cbSize);
|
||||
"bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
|
||||
passed_fmt->wFormatTag, passed_fmt->nChannels, passed_fmt->nSamplesPerSec,
|
||||
passed_fmt->nAvgBytesPerSec, passed_fmt->nBlockAlign,
|
||||
passed_fmt->wBitsPerSample, passed_fmt->cbSize);
|
||||
|
||||
/* **** */
|
||||
RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
|
||||
EnterCriticalSection(&(device->mixlock));
|
||||
|
||||
nSamplesPerSec = device->pwfx->nSamplesPerSec;
|
||||
bpp = device->pwfx->wBitsPerSample;
|
||||
chans = device->pwfx->nChannels;
|
||||
|
||||
oldpwfx = device->pwfx;
|
||||
device->pwfx = DSOUND_CopyFormat(wfex);
|
||||
old_fmt = device->pwfx;
|
||||
device->pwfx = DSOUND_CopyFormat(passed_fmt);
|
||||
fmtex = (WAVEFORMATEXTENSIBLE *)device->pwfx;
|
||||
if (device->pwfx == NULL) {
|
||||
device->pwfx = oldpwfx;
|
||||
oldpwfx = NULL;
|
||||
device->pwfx = old_fmt;
|
||||
old_fmt = NULL;
|
||||
err = DSERR_OUTOFMEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
@ -377,21 +388,97 @@ HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex)
|
|||
DSOUND_PrimaryClose(device);
|
||||
|
||||
err = DSOUND_ReopenDevice(device, FALSE);
|
||||
if (FAILED(err))
|
||||
{
|
||||
WARN("DSOUND_ReopenDevice failed: %08x\n", err);
|
||||
goto done;
|
||||
if(SUCCEEDED(err))
|
||||
goto opened;
|
||||
|
||||
/* requested format failed, so try others */
|
||||
if(device->pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT){
|
||||
device->pwfx->wFormatTag = WAVE_FORMAT_PCM;
|
||||
device->pwfx->wBitsPerSample = 32;
|
||||
device->pwfx->nAvgBytesPerSec = passed_fmt->nSamplesPerSec * device->pwfx->nBlockAlign;
|
||||
device->pwfx->nBlockAlign = passed_fmt->nChannels * (device->pwfx->wBitsPerSample / 8);
|
||||
|
||||
err = DSOUND_ReopenDevice(device, FALSE);
|
||||
if(SUCCEEDED(err))
|
||||
goto opened;
|
||||
}
|
||||
|
||||
if(device->pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
|
||||
IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)){
|
||||
fmtex->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
|
||||
device->pwfx->wBitsPerSample = 32;
|
||||
device->pwfx->nAvgBytesPerSec = passed_fmt->nSamplesPerSec * device->pwfx->nBlockAlign;
|
||||
device->pwfx->nBlockAlign = passed_fmt->nChannels * (device->pwfx->wBitsPerSample / 8);
|
||||
|
||||
err = DSOUND_ReopenDevice(device, FALSE);
|
||||
if(SUCCEEDED(err))
|
||||
goto opened;
|
||||
}
|
||||
|
||||
device->pwfx->wBitsPerSample = 32;
|
||||
device->pwfx->nAvgBytesPerSec = passed_fmt->nSamplesPerSec * device->pwfx->nBlockAlign;
|
||||
device->pwfx->nBlockAlign = passed_fmt->nChannels * (device->pwfx->wBitsPerSample / 8);
|
||||
err = DSOUND_ReopenDevice(device, FALSE);
|
||||
if(SUCCEEDED(err))
|
||||
goto opened;
|
||||
|
||||
device->pwfx->wBitsPerSample = 16;
|
||||
device->pwfx->nAvgBytesPerSec = passed_fmt->nSamplesPerSec * device->pwfx->nBlockAlign;
|
||||
device->pwfx->nBlockAlign = passed_fmt->nChannels * (device->pwfx->wBitsPerSample / 8);
|
||||
err = DSOUND_ReopenDevice(device, FALSE);
|
||||
if(SUCCEEDED(err))
|
||||
goto opened;
|
||||
|
||||
device->pwfx->wBitsPerSample = 8;
|
||||
device->pwfx->nAvgBytesPerSec = passed_fmt->nSamplesPerSec * device->pwfx->nBlockAlign;
|
||||
device->pwfx->nBlockAlign = passed_fmt->nChannels * (device->pwfx->wBitsPerSample / 8);
|
||||
err = DSOUND_ReopenDevice(device, FALSE);
|
||||
if(SUCCEEDED(err))
|
||||
goto opened;
|
||||
|
||||
device->pwfx->nChannels = (passed_fmt->nChannels == 2) ? 1 : 2;
|
||||
device->pwfx->wBitsPerSample = passed_fmt->wBitsPerSample;
|
||||
device->pwfx->nAvgBytesPerSec = passed_fmt->nSamplesPerSec * device->pwfx->nBlockAlign;
|
||||
device->pwfx->nBlockAlign = passed_fmt->nChannels * (device->pwfx->wBitsPerSample / 8);
|
||||
err = DSOUND_ReopenDevice(device, FALSE);
|
||||
if(SUCCEEDED(err))
|
||||
goto opened;
|
||||
|
||||
device->pwfx->wBitsPerSample = 32;
|
||||
device->pwfx->nAvgBytesPerSec = passed_fmt->nSamplesPerSec * device->pwfx->nBlockAlign;
|
||||
device->pwfx->nBlockAlign = passed_fmt->nChannels * (device->pwfx->wBitsPerSample / 8);
|
||||
err = DSOUND_ReopenDevice(device, FALSE);
|
||||
if(SUCCEEDED(err))
|
||||
goto opened;
|
||||
|
||||
device->pwfx->wBitsPerSample = 16;
|
||||
device->pwfx->nAvgBytesPerSec = passed_fmt->nSamplesPerSec * device->pwfx->nBlockAlign;
|
||||
device->pwfx->nBlockAlign = passed_fmt->nChannels * (device->pwfx->wBitsPerSample / 8);
|
||||
err = DSOUND_ReopenDevice(device, FALSE);
|
||||
if(SUCCEEDED(err))
|
||||
goto opened;
|
||||
|
||||
device->pwfx->wBitsPerSample = 8;
|
||||
device->pwfx->nAvgBytesPerSec = passed_fmt->nSamplesPerSec * device->pwfx->nBlockAlign;
|
||||
device->pwfx->nBlockAlign = passed_fmt->nChannels * (device->pwfx->wBitsPerSample / 8);
|
||||
err = DSOUND_ReopenDevice(device, FALSE);
|
||||
if(SUCCEEDED(err))
|
||||
goto opened;
|
||||
|
||||
WARN("No formats could be opened\n");
|
||||
goto done;
|
||||
|
||||
opened:
|
||||
err = DSOUND_PrimaryOpen(device);
|
||||
if (err != DS_OK) {
|
||||
WARN("DSOUND_PrimaryOpen failed\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (wfex->nSamplesPerSec/100 != device->pwfx->nSamplesPerSec/100 && forced && device->buffer)
|
||||
if (passed_fmt->nSamplesPerSec/100 != device->pwfx->nSamplesPerSec/100 && forced && device->buffer)
|
||||
{
|
||||
DSOUND_PrimaryClose(device);
|
||||
device->pwfx->nSamplesPerSec = wfex->nSamplesPerSec;
|
||||
device->pwfx->nSamplesPerSec = passed_fmt->nSamplesPerSec;
|
||||
err = DSOUND_ReopenDevice(device, TRUE);
|
||||
if (FAILED(err))
|
||||
WARN("DSOUND_ReopenDevice(2) failed: %08x\n", err);
|
||||
|
@ -405,7 +492,9 @@ HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex)
|
|||
device->mixfunction = mixfunctions[device->pwfx->wBitsPerSample/8 - 1];
|
||||
device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1];
|
||||
|
||||
if (nSamplesPerSec != device->pwfx->nSamplesPerSec || bpp != device->pwfx->wBitsPerSample || chans != device->pwfx->nChannels) {
|
||||
if (old_fmt->nSamplesPerSec != device->pwfx->nSamplesPerSec ||
|
||||
old_fmt->wBitsPerSample != device->pwfx->wBitsPerSample ||
|
||||
old_fmt->nChannels != device->pwfx->nChannels) {
|
||||
IDirectSoundBufferImpl** dsb = device->buffers;
|
||||
for (i = 0; i < device->nrofbuffers; i++, dsb++) {
|
||||
/* **** */
|
||||
|
@ -426,7 +515,7 @@ done:
|
|||
RtlReleaseResource(&(device->buffer_list_lock));
|
||||
/* **** */
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, oldpwfx);
|
||||
HeapFree(GetProcessHeap(), 0, old_fmt);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -453,10 +542,11 @@ static HRESULT WINAPI PrimaryBufferImpl_SetFormat(
|
|||
static HRESULT WINAPI PrimaryBufferImpl_SetVolume(
|
||||
LPDIRECTSOUNDBUFFER iface,LONG vol
|
||||
) {
|
||||
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
|
||||
DirectSoundDevice *device = This->device;
|
||||
DWORD ampfactors;
|
||||
HRESULT hres = DS_OK;
|
||||
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
|
||||
DirectSoundDevice *device = This->device;
|
||||
HRESULT hr;
|
||||
float lvol, rvol;
|
||||
|
||||
TRACE("(%p,%d)\n", iface, vol);
|
||||
|
||||
if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
|
||||
|
@ -470,31 +560,64 @@ static HRESULT WINAPI PrimaryBufferImpl_SetVolume(
|
|||
}
|
||||
|
||||
/* **** */
|
||||
EnterCriticalSection(&(device->mixlock));
|
||||
EnterCriticalSection(&device->mixlock);
|
||||
|
||||
hr = IAudioStreamVolume_GetChannelVolume(device->volume, 0, &lvol);
|
||||
if(FAILED(hr)){
|
||||
LeaveCriticalSection(&device->mixlock);
|
||||
WARN("GetChannelVolume failed: %08x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
if(device->pwfx->nChannels > 1){
|
||||
hr = IAudioStreamVolume_GetChannelVolume(device->volume, 1, &rvol);
|
||||
if(FAILED(hr)){
|
||||
LeaveCriticalSection(&device->mixlock);
|
||||
WARN("GetChannelVolume failed: %08x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
}else
|
||||
rvol = 1;
|
||||
|
||||
device->volpan.dwTotalLeftAmpFactor = ((UINT16)(lvol * (DWORD)0xFFFF));
|
||||
device->volpan.dwTotalRightAmpFactor = ((UINT16)(rvol * (DWORD)0xFFFF));
|
||||
|
||||
waveOutGetVolume(device->hwo, &factors);
|
||||
device->volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff;
|
||||
device->volpan.dwTotalRightAmpFactor=ampfactors >> 16;
|
||||
DSOUND_AmpFactorToVolPan(&device->volpan);
|
||||
if (vol != device->volpan.lVolume) {
|
||||
device->volpan.lVolume=vol;
|
||||
DSOUND_RecalcVolPan(&device->volpan);
|
||||
ampfactors = (device->volpan.dwTotalLeftAmpFactor & 0xffff) | (device->volpan.dwTotalRightAmpFactor << 16);
|
||||
waveOutSetVolume(device->hwo, ampfactors);
|
||||
device->volpan.lVolume=vol;
|
||||
DSOUND_RecalcVolPan(&device->volpan);
|
||||
lvol = (float)((DWORD)(device->volpan.dwTotalLeftAmpFactor & 0xFFFF) / (float)0xFFFF);
|
||||
hr = IAudioStreamVolume_SetChannelVolume(device->volume, 0, lvol);
|
||||
if(FAILED(hr)){
|
||||
LeaveCriticalSection(&device->mixlock);
|
||||
WARN("SetChannelVolume failed: %08x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
if(device->pwfx->nChannels > 1){
|
||||
rvol = (float)((DWORD)(device->volpan.dwTotalRightAmpFactor & 0xFFFF) / (float)0xFFFF);
|
||||
hr = IAudioStreamVolume_SetChannelVolume(device->volume, 1, rvol);
|
||||
if(FAILED(hr)){
|
||||
LeaveCriticalSection(&device->mixlock);
|
||||
WARN("SetChannelVolume failed: %08x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&(device->mixlock));
|
||||
/* **** */
|
||||
|
||||
return hres;
|
||||
return DS_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI PrimaryBufferImpl_GetVolume(
|
||||
LPDIRECTSOUNDBUFFER iface,LPLONG vol
|
||||
) {
|
||||
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
|
||||
DirectSoundDevice *device = This->device;
|
||||
DWORD ampfactors;
|
||||
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
|
||||
DirectSoundDevice *device = This->device;
|
||||
float lvol, rvol;
|
||||
HRESULT hr;
|
||||
TRACE("(%p,%p)\n", iface, vol);
|
||||
|
||||
if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
|
||||
|
@ -507,12 +630,33 @@ static HRESULT WINAPI PrimaryBufferImpl_GetVolume(
|
|||
return DSERR_INVALIDPARAM;
|
||||
}
|
||||
|
||||
waveOutGetVolume(device->hwo, &factors);
|
||||
device->volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff;
|
||||
device->volpan.dwTotalRightAmpFactor=ampfactors >> 16;
|
||||
EnterCriticalSection(&device->mixlock);
|
||||
|
||||
hr = IAudioStreamVolume_GetChannelVolume(device->volume, 0, &lvol);
|
||||
if(FAILED(hr)){
|
||||
LeaveCriticalSection(&device->mixlock);
|
||||
WARN("GetChannelVolume failed: %08x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
if(device->pwfx->nChannels > 1){
|
||||
hr = IAudioStreamVolume_GetChannelVolume(device->volume, 1, &rvol);
|
||||
if(FAILED(hr)){
|
||||
LeaveCriticalSection(&device->mixlock);
|
||||
WARN("GetChannelVolume failed: %08x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
}else
|
||||
rvol = 1;
|
||||
|
||||
device->volpan.dwTotalLeftAmpFactor = ((UINT16)(lvol * (DWORD)0xFFFF));
|
||||
device->volpan.dwTotalRightAmpFactor = ((UINT16)(rvol * (DWORD)0xFFFF));
|
||||
|
||||
DSOUND_AmpFactorToVolPan(&device->volpan);
|
||||
*vol = device->volpan.lVolume;
|
||||
|
||||
LeaveCriticalSection(&device->mixlock);
|
||||
|
||||
return DS_OK;
|
||||
}
|
||||
|
||||
|
@ -776,10 +920,10 @@ static HRESULT WINAPI PrimaryBufferImpl_SetCurrentPosition(
|
|||
static HRESULT WINAPI PrimaryBufferImpl_SetPan(
|
||||
LPDIRECTSOUNDBUFFER iface,LONG pan
|
||||
) {
|
||||
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
|
||||
DirectSoundDevice *device = This->device;
|
||||
DWORD ampfactors;
|
||||
HRESULT hres = DS_OK;
|
||||
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
|
||||
DirectSoundDevice *device = This->device;
|
||||
float lvol, rvol;
|
||||
HRESULT hr;
|
||||
TRACE("(%p,%d)\n", iface, pan);
|
||||
|
||||
if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
|
||||
|
@ -793,31 +937,65 @@ static HRESULT WINAPI PrimaryBufferImpl_SetPan(
|
|||
}
|
||||
|
||||
/* **** */
|
||||
EnterCriticalSection(&(device->mixlock));
|
||||
EnterCriticalSection(&device->mixlock);
|
||||
|
||||
hr = IAudioStreamVolume_GetChannelVolume(device->volume, 0, &lvol);
|
||||
if(FAILED(hr)){
|
||||
LeaveCriticalSection(&device->mixlock);
|
||||
WARN("GetChannelVolume failed: %08x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
if(device->pwfx->nChannels > 1){
|
||||
hr = IAudioStreamVolume_GetChannelVolume(device->volume, 1, &rvol);
|
||||
if(FAILED(hr)){
|
||||
LeaveCriticalSection(&device->mixlock);
|
||||
WARN("GetChannelVolume failed: %08x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
}else
|
||||
rvol = 1;
|
||||
|
||||
device->volpan.dwTotalLeftAmpFactor = ((UINT16)(lvol * (DWORD)0xFFFF));
|
||||
device->volpan.dwTotalRightAmpFactor = ((UINT16)(rvol * (DWORD)0xFFFF));
|
||||
|
||||
waveOutGetVolume(device->hwo, &factors);
|
||||
device->volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff;
|
||||
device->volpan.dwTotalRightAmpFactor=ampfactors >> 16;
|
||||
DSOUND_AmpFactorToVolPan(&device->volpan);
|
||||
if (pan != device->volpan.lPan) {
|
||||
device->volpan.lPan=pan;
|
||||
DSOUND_RecalcVolPan(&device->volpan);
|
||||
ampfactors = (device->volpan.dwTotalLeftAmpFactor & 0xffff) | (device->volpan.dwTotalRightAmpFactor << 16);
|
||||
waveOutSetVolume(device->hwo, ampfactors);
|
||||
|
||||
lvol = (float)((DWORD)(device->volpan.dwTotalLeftAmpFactor & 0xFFFF) / (float)0xFFFF);
|
||||
hr = IAudioStreamVolume_SetChannelVolume(device->volume, 0, lvol);
|
||||
if(FAILED(hr)){
|
||||
LeaveCriticalSection(&device->mixlock);
|
||||
WARN("SetChannelVolume failed: %08x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
if(device->pwfx->nChannels > 1){
|
||||
rvol = (float)((DWORD)(device->volpan.dwTotalRightAmpFactor & 0xFFFF) / (float)0xFFFF);
|
||||
hr = IAudioStreamVolume_SetChannelVolume(device->volume, 1, rvol);
|
||||
if(FAILED(hr)){
|
||||
LeaveCriticalSection(&device->mixlock);
|
||||
WARN("SetChannelVolume failed: %08x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&(device->mixlock));
|
||||
LeaveCriticalSection(&device->mixlock);
|
||||
/* **** */
|
||||
|
||||
return hres;
|
||||
return DS_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI PrimaryBufferImpl_GetPan(
|
||||
LPDIRECTSOUNDBUFFER iface,LPLONG pan
|
||||
) {
|
||||
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
|
||||
DirectSoundDevice *device = This->device;
|
||||
DWORD ampfactors;
|
||||
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
|
||||
DirectSoundDevice *device = This->device;
|
||||
float lvol, rvol;
|
||||
HRESULT hr;
|
||||
TRACE("(%p,%p)\n", iface, pan);
|
||||
|
||||
if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
|
||||
|
@ -830,11 +1008,33 @@ static HRESULT WINAPI PrimaryBufferImpl_GetPan(
|
|||
return DSERR_INVALIDPARAM;
|
||||
}
|
||||
|
||||
waveOutGetVolume(device->hwo, &factors);
|
||||
device->volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff;
|
||||
device->volpan.dwTotalRightAmpFactor=ampfactors >> 16;
|
||||
EnterCriticalSection(&device->mixlock);
|
||||
|
||||
hr = IAudioStreamVolume_GetChannelVolume(device->volume, 0, &lvol);
|
||||
if(FAILED(hr)){
|
||||
LeaveCriticalSection(&device->mixlock);
|
||||
WARN("GetChannelVolume failed: %08x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
if(device->pwfx->nChannels > 1){
|
||||
hr = IAudioStreamVolume_GetChannelVolume(device->volume, 1, &rvol);
|
||||
if(FAILED(hr)){
|
||||
LeaveCriticalSection(&device->mixlock);
|
||||
WARN("GetChannelVolume failed: %08x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
}else
|
||||
rvol = 1;
|
||||
|
||||
device->volpan.dwTotalLeftAmpFactor = ((UINT16)(lvol * (DWORD)0xFFFF));
|
||||
device->volpan.dwTotalRightAmpFactor = ((UINT16)(rvol * (DWORD)0xFFFF));
|
||||
|
||||
DSOUND_AmpFactorToVolPan(&device->volpan);
|
||||
*pan = device->volpan.lPan;
|
||||
|
||||
LeaveCriticalSection(&device->mixlock);
|
||||
|
||||
return DS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ START_TEST(dependency)
|
|||
ok(!GetModuleHandle("dsound.dll"), "dsound.dll was already loaded!\n");
|
||||
|
||||
hr = IMMDevice_Activate(dev, &IID_IDirectSound8, CLSCTX_INPROC_SERVER, NULL, (void**)&ds8);
|
||||
todo_wine ok(hr == S_OK, "Activating ds8 interface failed: 0x%08x\n", hr);
|
||||
ok(hr == S_OK, "Activating ds8 interface failed: 0x%08x\n", hr);
|
||||
if (hr == S_OK)
|
||||
{
|
||||
ok(GetModuleHandle("dsound.dll") != NULL, "dsound.dll not loaded!\n");
|
||||
|
|
Loading…
Reference in New Issue