Commit e786998d authored by Andrew Eikum's avatar Andrew Eikum Committed by Alexandre Julliard

dsound: Reimplement rendering devices on mmdevapi.

parent 4b8a2963
MODULE = dsound.dll MODULE = dsound.dll
IMPORTLIB = dsound IMPORTLIB = dsound
IMPORTS = dxguid uuid winmm ole32 advapi32 IMPORTS = dxguid uuid winmm ole32 advapi32 user32
C_SRCS = \ C_SRCS = \
buffer.c \ buffer.c \
......
...@@ -23,12 +23,12 @@ ...@@ -23,12 +23,12 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#define COBJMACROS
#define NONAMELESSSTRUCT #define NONAMELESSSTRUCT
#define NONAMELESSUNION #define NONAMELESSUNION
#include "windef.h" #include "windef.h"
#include "winbase.h" #include "winbase.h"
#include "winuser.h" #include "winuser.h"
#include "mmsystem.h"
#include "winternl.h" #include "winternl.h"
#include "mmddk.h" #include "mmddk.h"
#include "wingdi.h" #include "wingdi.h"
...@@ -1248,6 +1248,10 @@ ULONG DirectSoundDevice_Release(DirectSoundDevice * device) ...@@ -1248,6 +1248,10 @@ ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE); RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);
RtlReleaseResource(&(device->buffer_list_lock)); 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 */ /* It is allowed to release this object even when buffers are playing */
if (device->buffers) { if (device->buffers) {
WARN("%d secondary buffers not released\n", device->nrofbuffers); WARN("%d secondary buffers not released\n", device->nrofbuffers);
...@@ -1264,9 +1268,14 @@ ULONG DirectSoundDevice_Release(DirectSoundDevice * device) ...@@ -1264,9 +1268,14 @@ ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
if (hr != DS_OK) if (hr != DS_OK)
WARN("DSOUND_PrimaryDestroy failed\n"); WARN("DSOUND_PrimaryDestroy failed\n");
waveOutClose(device->hwo); if(device->client)
IAudioClient_Release(device->client);
DSOUND_renderer[device->drvdesc.dnDevNode] = NULL; 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->tmp_buffer);
HeapFree(GetProcessHeap(), 0, device->mix_buffer); HeapFree(GetProcessHeap(), 0, device->mix_buffer);
...@@ -1334,14 +1343,57 @@ HRESULT DirectSoundDevice_GetCaps( ...@@ -1334,14 +1343,57 @@ HRESULT DirectSoundDevice_GetCaps(
return DS_OK; 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 DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
{ {
HRESULT hr = DS_OK; HRESULT hr = DS_OK;
unsigned wod, wodn;
BOOLEAN found = FALSE;
GUID devGUID; GUID devGUID;
DirectSoundDevice * device = *ppDevice; DirectSoundDevice *device;
WAVEOUTCAPSA woc; IMMDevice *mmdevice;
TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID)); TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
...@@ -1354,130 +1406,97 @@ HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcG ...@@ -1354,130 +1406,97 @@ HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcG
if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL)) if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
lpcGUID = &DSDEVID_DefaultPlayback; lpcGUID = &DSDEVID_DefaultPlayback;
if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultCapture) ||
IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoiceCapture))
return DSERR_NODRIVER;
if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) { if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
WARN("invalid parameter: lpcGUID\n"); WARN("invalid parameter: lpcGUID\n");
return DSERR_INVALIDPARAM; return DSERR_INVALIDPARAM;
} }
/* Enumerate WINMM audio devices and find the one we want */ hr = get_mmdevice(eRender, &devGUID, &mmdevice);
wodn = waveOutGetNumDevs(); if(FAILED(hr))
if (!wodn) { return hr;
WARN("no driver\n");
return DSERR_NODRIVER;
}
for (wod=0; wod<wodn; wod++) {
if (IsEqualGUID( &devGUID, &DSOUND_renderer_guids[wod])) {
found = TRUE;
break;
}
}
if (found == FALSE) { EnterCriticalSection(&DSOUND_renderers_lock);
WARN("No device found matching given ID!\n");
return DSERR_NODRIVER;
}
if (DSOUND_renderer[wod]) { LIST_FOR_EACH_ENTRY(device, &DSOUND_renderers, DirectSoundDevice, entry){
if (IsEqualGUID(&devGUID, &DSOUND_renderer[wod]->guid)) { if(IsEqualGUID(&device->guid, &devGUID)){
device = DSOUND_renderer[wod]; IMMDevice_Release(mmdevice);
DirectSoundDevice_AddRef(device); DirectSoundDevice_AddRef(device);
*ppDevice = device; *ppDevice = device;
LeaveCriticalSection(&DSOUND_renderers_lock);
return DS_OK; return DS_OK;
} else {
ERR("device GUID doesn't match\n");
hr = DSERR_GENERIC;
return hr;
} }
} else { }
hr = DirectSoundDevice_Create(&device); hr = DirectSoundDevice_Create(&device);
if (hr != DS_OK) { if(FAILED(hr)){
WARN("DirectSoundDevice_Create failed\n"); WARN("DirectSoundDevice_Create failed\n");
IMMDevice_Release(mmdevice);
LeaveCriticalSection(&DSOUND_renderers_lock);
return hr; return hr;
} }
}
*ppDevice = device; device->mmdevice = mmdevice;
device->guid = devGUID; device->guid = devGUID;
device->drvdesc.dnDevNode = wod;
hr = DSOUND_ReopenDevice(device, FALSE); hr = DSOUND_ReopenDevice(device, FALSE);
if (FAILED(hr)) if (FAILED(hr))
{ {
HeapFree(GetProcessHeap(), 0, device);
LeaveCriticalSection(&DSOUND_renderers_lock);
IMMDevice_Release(mmdevice);
WARN("DSOUND_ReopenDevice failed: %08x\n", hr); WARN("DSOUND_ReopenDevice failed: %08x\n", hr);
return 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)); ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
if ((woc.dwFormats & WAVE_FORMAT_1M08) ||
(woc.dwFormats & WAVE_FORMAT_2M08) || if(DSOUND_check_supported(device->client, 11025, 8, 1) ||
(woc.dwFormats & WAVE_FORMAT_4M08) || DSOUND_check_supported(device->client, 22050, 8, 1) ||
(woc.dwFormats & WAVE_FORMAT_48M08) || DSOUND_check_supported(device->client, 44100, 8, 1) ||
(woc.dwFormats & WAVE_FORMAT_96M08)) { DSOUND_check_supported(device->client, 48000, 8, 1) ||
device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT; DSOUND_check_supported(device->client, 96000, 8, 1))
device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO; device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYMONO;
}
if ((woc.dwFormats & WAVE_FORMAT_1M16) || if(DSOUND_check_supported(device->client, 11025, 16, 1) ||
(woc.dwFormats & WAVE_FORMAT_2M16) || DSOUND_check_supported(device->client, 22050, 16, 1) ||
(woc.dwFormats & WAVE_FORMAT_4M16) || DSOUND_check_supported(device->client, 44100, 16, 1) ||
(woc.dwFormats & WAVE_FORMAT_48M16) || DSOUND_check_supported(device->client, 48000, 16, 1) ||
(woc.dwFormats & WAVE_FORMAT_96M16)) { DSOUND_check_supported(device->client, 96000, 16, 1))
device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT; device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYMONO;
device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
} if(DSOUND_check_supported(device->client, 11025, 8, 2) ||
if ((woc.dwFormats & WAVE_FORMAT_1S08) || DSOUND_check_supported(device->client, 22050, 8, 2) ||
(woc.dwFormats & WAVE_FORMAT_2S08) || DSOUND_check_supported(device->client, 44100, 8, 2) ||
(woc.dwFormats & WAVE_FORMAT_4S08) || DSOUND_check_supported(device->client, 48000, 8, 2) ||
(woc.dwFormats & WAVE_FORMAT_48S08) || DSOUND_check_supported(device->client, 96000, 8, 2))
(woc.dwFormats & WAVE_FORMAT_96S08)) { device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYSTEREO;
device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO; if(DSOUND_check_supported(device->client, 11025, 16, 2) ||
} DSOUND_check_supported(device->client, 22050, 16, 2) ||
if ((woc.dwFormats & WAVE_FORMAT_1S16) || DSOUND_check_supported(device->client, 44100, 16, 2) ||
(woc.dwFormats & WAVE_FORMAT_2S16) || DSOUND_check_supported(device->client, 48000, 16, 2) ||
(woc.dwFormats & WAVE_FORMAT_4S16) || DSOUND_check_supported(device->client, 96000, 16, 2))
(woc.dwFormats & WAVE_FORMAT_48S16) || device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO;
(woc.dwFormats & WAVE_FORMAT_96S16)) {
device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
}
if(ds_emuldriver)
device->drvcaps.dwFlags |= DSCAPS_EMULDRIVER;
device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN; device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX; device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
ZeroMemory(&device->volpan, sizeof(device->volpan)); ZeroMemory(&device->volpan, sizeof(device->volpan));
hr = DSOUND_PrimaryCreate(device); hr = DSOUND_PrimaryCreate(device);
if (hr == DS_OK) { if (hr == DS_OK)
UINT triggertime = DS_TIME_DEL, res = DS_TIME_RES, id; device->timerID = DSOUND_create_timer(DSOUND_timer, (DWORD_PTR)device);
TIMECAPS time; else
WARN("DSOUND_PrimaryCreate failed: %08x\n", hr);
DSOUND_renderer[device->drvdesc.dnDevNode] = device; *ppDevice = device;
timeGetDevCaps(&time, sizeof(TIMECAPS)); list_add_tail(&DSOUND_renderers, &device->entry);
TRACE("Minimum timer resolution: %u, max timer: %u\n", time.wPeriodMin, time.wPeriodMax);
if (triggertime < time.wPeriodMin) LeaveCriticalSection(&DSOUND_renderers_lock);
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");
}
return hr; return hr;
} }
......
...@@ -50,17 +50,31 @@ ...@@ -50,17 +50,31 @@
#include "dsconf.h" #include "dsconf.h"
#include "ks.h" #include "ks.h"
#include "rpcproxy.h" #include "rpcproxy.h"
#include "rpc.h"
#include "rpcndr.h"
#include "unknwn.h"
#include "oleidl.h"
#include "shobjidl.h"
#include "initguid.h" #include "initguid.h"
#include "ksmedia.h" #include "ksmedia.h"
#include "propkey.h"
#include "devpkey.h"
#include "dsound_private.h" #include "dsound_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(dsound); 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_renderer_guids[MAXWAVEDRIVERS];
GUID DSOUND_capture_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) HRESULT mmErr(UINT err)
{ {
switch(err) { switch(err) {
...@@ -196,6 +210,117 @@ static const char * get_device_id(LPCGUID pGuid) ...@@ -196,6 +210,117 @@ static const char * get_device_id(LPCGUID pGuid)
return debugstr_guid(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] * GetDeviceID [DSOUND.9]
* *
...@@ -218,34 +343,51 @@ static const char * get_device_id(LPCGUID pGuid) ...@@ -218,34 +343,51 @@ static const char * get_device_id(LPCGUID pGuid)
*/ */
HRESULT WINAPI GetDeviceID(LPCGUID pGuidSrc, LPGUID pGuidDest) 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); TRACE("(%s,%p)\n", get_device_id(pGuidSrc),pGuidDest);
if ( pGuidSrc == NULL) { if(!pGuidSrc || !pGuidDest)
WARN("invalid parameter: pGuidSrc == NULL\n");
return DSERR_INVALIDPARAM; return DSERR_INVALIDPARAM;
}
if ( pGuidDest == NULL ) { devenum = get_mmdevenum();
WARN("invalid parameter: pGuidDest == NULL\n"); if(!devenum)
return DSERR_INVALIDPARAM; return DSERR_GENERIC;
}
if ( IsEqualGUID( &DSDEVID_DefaultPlayback, pGuidSrc ) || if(IsEqualGUID(&DSDEVID_DefaultPlayback, pGuidSrc)){
IsEqualGUID( &DSDEVID_DefaultVoicePlayback, pGuidSrc ) ) { role = eMultimedia;
*pGuidDest = DSOUND_renderer_guids[ds_default_playback]; flow = eRender;
TRACE("returns %s\n", get_device_id(pGuidDest)); }else if(IsEqualGUID(&DSDEVID_DefaultVoicePlayback, pGuidSrc)){
return DS_OK; 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(role != (ERole)-1 && flow != (EDataFlow)-1){
IMMDevice *device;
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum,
flow, role, &device);
if(FAILED(hr)){
WARN("GetDefaultAudioEndpoint failed: %08x\n", hr);
return DSERR_NODRIVER;
} }
if ( IsEqualGUID( &DSDEVID_DefaultCapture, pGuidSrc ) || hr = get_mmdevice_guid(device, NULL, pGuidDest);
IsEqualGUID( &DSDEVID_DefaultVoiceCapture, pGuidSrc ) ) { IMMDevice_Release(device);
*pGuidDest = DSOUND_capture_guids[ds_default_capture];
TRACE("returns %s\n", get_device_id(pGuidDest)); return (hr == S_OK) ? DS_OK : hr;
return DS_OK;
} }
*pGuidDest = *pGuidSrc; *pGuidDest = *pGuidSrc;
TRACE("returns %s\n", get_device_id(pGuidDest));
return DS_OK; return DS_OK;
} }
...@@ -297,6 +439,141 @@ HRESULT WINAPI DirectSoundEnumerateA( ...@@ -297,6 +439,141 @@ HRESULT WINAPI DirectSoundEnumerateA(
return DirectSoundEnumerateW(a_to_w_callback, &context); 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] * DirectSoundEnumerateW [DSOUND.3]
* *
...@@ -314,17 +591,7 @@ HRESULT WINAPI DirectSoundEnumerateW( ...@@ -314,17 +591,7 @@ HRESULT WINAPI DirectSoundEnumerateW(
LPDSENUMCALLBACKW lpDSEnumCallback, LPDSENUMCALLBACKW lpDSEnumCallback,
LPVOID lpContext ) LPVOID lpContext )
{ {
unsigned devs, wod; TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext);
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);
if (lpDSEnumCallback == NULL) { if (lpDSEnumCallback == NULL) {
WARN("invalid parameter: lpDSEnumCallback == NULL\n"); WARN("invalid parameter: lpDSEnumCallback == NULL\n");
...@@ -333,36 +600,8 @@ HRESULT WINAPI DirectSoundEnumerateW( ...@@ -333,36 +600,8 @@ HRESULT WINAPI DirectSoundEnumerateW(
setup_dsound_options(); setup_dsound_options();
devs = waveOutGetNumDevs(); return enumerate_mmdevices(eRender, DSOUND_renderer_guids,
if (devs > 0) { lpDSEnumCallback, lpContext);
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;
} }
/*************************************************************************** /***************************************************************************
...@@ -645,15 +884,15 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved) ...@@ -645,15 +884,15 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved)
case DLL_PROCESS_ATTACH: case DLL_PROCESS_ATTACH:
TRACE("DLL_PROCESS_ATTACH\n"); TRACE("DLL_PROCESS_ATTACH\n");
for (i = 0; i < MAXWAVEDRIVERS; i++) { for (i = 0; i < MAXWAVEDRIVERS; i++) {
DSOUND_renderer[i] = NULL;
DSOUND_capture[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); INIT_GUID(DSOUND_capture_guids[i], 0xbd6dd71b, 0x3deb, 0x11d1, 0xb1, 0x71, 0x00, 0xc0, 0x4f, 0xc2, 0x00, 0x00 + i);
} }
instance = hInstDLL; instance = hInstDLL;
DisableThreadLibraryCalls(hInstDLL); DisableThreadLibraryCalls(hInstDLL);
/* Increase refcount on dsound by 1 */ /* Increase refcount on dsound by 1 */
GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)hInstDLL, &hInstDLL); GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)hInstDLL, &hInstDLL);
InitializeCriticalSection(&DSOUND_renderers_lock);
InitializeCriticalSection(&g_devenum_lock);
break; break;
case DLL_PROCESS_DETACH: case DLL_PROCESS_DETACH:
TRACE("DLL_PROCESS_DETACH\n"); TRACE("DLL_PROCESS_DETACH\n");
......
...@@ -23,6 +23,11 @@ ...@@ -23,6 +23,11 @@
#define DS_TIME_RES 2 /* Resolution of multimedia timer */ #define DS_TIME_RES 2 /* Resolution of multimedia timer */
#define DS_TIME_DEL 10 /* Delay of multimedia timer callback, and duration of HEL fragment */ #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" #include "wine/list.h"
extern int ds_emuldriver DECLSPEC_HIDDEN; extern int ds_emuldriver DECLSPEC_HIDDEN;
...@@ -132,9 +137,8 @@ struct DirectSoundDevice ...@@ -132,9 +137,8 @@ struct DirectSoundDevice
DSDRIVERCAPS drvcaps; DSDRIVERCAPS drvcaps;
DWORD priolevel; DWORD priolevel;
PWAVEFORMATEX pwfx; PWAVEFORMATEX pwfx;
HWAVEOUT hwo;
LPWAVEHDR pwave;
UINT timerID, pwplay, pwqueue, prebuf, helfrags; UINT timerID, pwplay, pwqueue, prebuf, helfrags;
UINT64 last_pos_bytes;
DWORD fraglen; DWORD fraglen;
LPBYTE buffer; LPBYTE buffer;
DWORD writelead, buflen, state, playpos, mixpos; DWORD writelead, buflen, state, playpos, mixpos;
...@@ -156,6 +160,14 @@ struct DirectSoundDevice ...@@ -156,6 +160,14 @@ struct DirectSoundDevice
IDirectSound3DListenerImpl* listener; IDirectSound3DListenerImpl* listener;
DS3DLISTENER ds3dl; DS3DLISTENER ds3dl;
BOOL ds3dl_need_recalc; 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 */ /* reference counted buffer memory for duplicated buffer memory */
...@@ -397,7 +409,6 @@ void DSOUND_MixToTemporary(const IDirectSoundBufferImpl *dsb, DWORD writepos, DW ...@@ -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; 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_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 */ /* sound3d.c */
...@@ -416,12 +427,16 @@ HRESULT DSOUND_CaptureCreate8(REFIID riid, LPDIRECTSOUNDCAPTURE8 *ppDSC8) DECLSP ...@@ -416,12 +427,16 @@ HRESULT DSOUND_CaptureCreate8(REFIID riid, LPDIRECTSOUNDCAPTURE8 *ppDSC8) DECLSP
#define DSOUND_FREQSHIFT (20) #define DSOUND_FREQSHIFT (20)
extern DirectSoundDevice* DSOUND_renderer[MAXWAVEDRIVERS] DECLSPEC_HIDDEN; extern CRITICAL_SECTION DSOUND_renderers_lock DECLSPEC_HIDDEN;
extern GUID DSOUND_renderer_guids[MAXWAVEDRIVERS] DECLSPEC_HIDDEN; extern struct list DSOUND_renderers DECLSPEC_HIDDEN;
extern DirectSoundCaptureDevice * DSOUND_capture[MAXWAVEDRIVERS] 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; extern GUID DSOUND_capture_guids[MAXWAVEDRIVERS] DECLSPEC_HIDDEN;
HRESULT mmErr(UINT err) DECLSPEC_HIDDEN; HRESULT mmErr(UINT err) DECLSPEC_HIDDEN;
void setup_dsound_options(void) DECLSPEC_HIDDEN; void setup_dsound_options(void) DECLSPEC_HIDDEN;
const char * dumpCooperativeLevel(DWORD level) 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 @@ ...@@ -26,6 +26,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <math.h> /* Insomnia - pow() function */ #include <math.h> /* Insomnia - pow() function */
#define COBJMACROS
#define NONAMELESSSTRUCT #define NONAMELESSSTRUCT
#define NONAMELESSUNION #define NONAMELESSUNION
#include "windef.h" #include "windef.h"
...@@ -742,17 +743,21 @@ static DWORD DSOUND_MixToPrimary(const DirectSoundDevice *device, DWORD writepos ...@@ -742,17 +743,21 @@ static DWORD DSOUND_MixToPrimary(const DirectSoundDevice *device, DWORD writepos
static void DSOUND_WaveQueue(DirectSoundDevice *device, BOOL force) 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); TRACE("(%p)\n", device);
/* calculate the current wave frag position */ /* calculate the current wave frag position */
wave_fragpos = (device->pwplay + device->pwqueue) % device->helfrags; wave_fragpos = (device->pwplay + device->pwqueue) % device->helfrags;
/* calculate the current wave write position */ /* 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", TRACE("wave_fragpos = %i, buf_offs_bytes = %i, pwqueue = %i, prebuf = %i\n",
wave_fragpos, wave_writepos, device->pwqueue, device->prebuf); wave_fragpos, buf_offs_bytes, device->pwqueue, device->prebuf);
if (!force) if (!force)
{ {
...@@ -776,23 +781,50 @@ static void DSOUND_WaveQueue(DirectSoundDevice *device, BOOL force) ...@@ -776,23 +781,50 @@ static void DSOUND_WaveQueue(DirectSoundDevice *device, BOOL force)
TRACE("prebuf_frags = %i\n", prebuf_frags); TRACE("prebuf_frags = %i\n", prebuf_frags);
if(!prebuf_frags)
return;
/* adjust queue */ /* adjust queue */
device->pwqueue += prebuf_frags; device->pwqueue += prebuf_frags;
/* get out of CS when calling the wave system */ prebuf_frames = ((prebuf_frags + wave_fragpos > device->helfrags) ?
LeaveCriticalSection(&(device->mixlock)); (prebuf_frags + wave_fragpos - device->helfrags) :
/* **** */ (prebuf_frags)) * device->fraglen / device->pwfx->nBlockAlign;
/* queue up the new buffers */ hr = IAudioRenderClient_GetBuffer(device->render, prebuf_frames, &buffer);
for(i=0; i<prebuf_frags; i++){ if(FAILED(hr)){
TRACE("queueing wave buffer %i\n", wave_fragpos); WARN("GetBuffer failed: %08x\n", hr);
waveOutWrite(device->hwo, &device->pwave[wave_fragpos], sizeof(WAVEHDR)); return;
wave_fragpos++;
wave_fragpos %= device->helfrags;
} }
/* **** */ memcpy(buffer, device->buffer + buf_offs_bytes,
EnterCriticalSection(&(device->mixlock)); 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); TRACE("queue now = %i\n", device->pwqueue);
} }
...@@ -804,10 +836,39 @@ static void DSOUND_WaveQueue(DirectSoundDevice *device, BOOL force) ...@@ -804,10 +836,39 @@ static void DSOUND_WaveQueue(DirectSoundDevice *device, BOOL force)
*/ */
static void DSOUND_PerformMix(DirectSoundDevice *device) static void DSOUND_PerformMix(DirectSoundDevice *device)
{ {
UINT64 clock_pos, clock_freq, pos_bytes;
UINT delta_frags;
HRESULT hr;
TRACE("(%p)\n", device); 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) { if (device->priolevel != DSSCL_WRITEPRIMARY) {
BOOL recover = FALSE, all_stopped = FALSE; BOOL recover = FALSE, all_stopped = FALSE;
...@@ -978,13 +1039,6 @@ void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD_PTR dwUser, ...@@ -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("(%d,%d,0x%lx,0x%lx,0x%lx)\n",timerID,msg,dwUser,dw1,dw2);
TRACE("entering at %d\n", start_time); 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); RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);
if (device->ref) if (device->ref)
...@@ -995,37 +1049,3 @@ void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD_PTR dwUser, ...@@ -995,37 +1049,3 @@ void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
end_time = GetTickCount(); end_time = GetTickCount();
TRACE("completed processing at %d, duration = %d\n", end_time, end_time - start_time); 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 @@ ...@@ -25,6 +25,7 @@
#include <stdarg.h> #include <stdarg.h>
#define COBJMACROS
#define NONAMELESSSTRUCT #define NONAMELESSSTRUCT
#define NONAMELESSUNION #define NONAMELESSUNION
#include "windef.h" #include "windef.h"
...@@ -83,32 +84,86 @@ static void DSOUND_RecalcPrimary(DirectSoundDevice *device) ...@@ -83,32 +84,86 @@ static void DSOUND_RecalcPrimary(DirectSoundDevice *device)
HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave) HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
{ {
HRESULT hres = DS_OK; HRESULT hres;
TRACE("(%p, %d)\n", device, forcewave); TRACE("(%p, %d)\n", device, forcewave);
waveOutClose(device->hwo); 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; device->drvdesc.dwFlags = 0;
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;
}
hres = mmErr(waveOutOpen(&(device->hwo), device->drvdesc.dnDevNode, /* buffer size = 200 * 100000 (100 ns) = 2.0 seconds */
device->pwfx, (DWORD_PTR)DSOUND_callback, (DWORD_PTR)device, hres = IAudioClient_Initialize(device->client,
CALLBACK_FUNCTION | WAVE_MAPPED)); AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST,
if (FAILED(hres)) { 200 * 100000, 50000, device->pwfx, NULL);
WARN("waveOutOpen failed: %08x\n", hres); if(FAILED(hres)){
IAudioClient_Release(device->client);
device->client = NULL;
WARN("Initialize failed: %08x\n", hres);
return 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; 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) static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
{ {
DWORD buflen; DWORD buflen;
HRESULT err = DS_OK;
LPBYTE newbuf; LPBYTE newbuf;
LPWAVEHDR headers = NULL;
DWORD overshot;
unsigned int c;
TRACE("(%p)\n", device); TRACE("(%p)\n", device);
...@@ -128,9 +183,6 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device) ...@@ -128,9 +183,6 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
if (device->state == STATE_PLAYING) device->state = STATE_STARTING; if (device->state == STATE_PLAYING) device->state = STATE_STARTING;
else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED; 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); TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
/* reallocate emulated primary buffer */ /* reallocate emulated primary buffer */
...@@ -146,70 +198,33 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device) ...@@ -146,70 +198,33 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
} }
DSOUND_RecalcPrimary(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->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; TRACE("fraglen=%d\n", 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->mixfunction = mixfunctions[device->pwfx->wBitsPerSample/8 - 1];
device->normfunction = normfunctions[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->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0);
FillMemory(device->mix_buffer, device->mix_buffer_len, 0); FillMemory(device->mix_buffer, device->mix_buffer_len, 0);
device->pwplay = device->pwqueue = device->playpos = device->mixpos = 0; device->last_pos_bytes = device->pwplay = device->pwqueue = device->playpos = device->mixpos = 0;
return err; return DS_OK;
} }
static void DSOUND_PrimaryClose(DirectSoundDevice *device) 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 */ device->pwqueue = (DWORD)-1; /* resetting queues */
waveOutReset(device->hwo);
for (c=0; c<device->helfrags; c++) if(device->client){
waveOutUnprepareHeader(device->hwo, &device->pwave[c], sizeof(WAVEHDR)); hr = IAudioClient_Stop(device->client);
/* **** */ if(FAILED(hr))
EnterCriticalSection(&(device->mixlock)); WARN("Stop failed: %08x\n", hr);
}
/* clear the queue */ /* clear the queue */
device->pwqueue = 0; device->pwqueue = 0;
...@@ -240,7 +255,6 @@ HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device) ...@@ -240,7 +255,6 @@ HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device)
EnterCriticalSection(&(device->mixlock)); EnterCriticalSection(&(device->mixlock));
DSOUND_PrimaryClose(device); DSOUND_PrimaryClose(device);
HeapFree(GetProcessHeap(),0,device->pwave);
HeapFree(GetProcessHeap(),0,device->pwfx); HeapFree(GetProcessHeap(),0,device->pwfx);
device->pwfx=NULL; device->pwfx=NULL;
...@@ -252,32 +266,32 @@ HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device) ...@@ -252,32 +266,32 @@ HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device)
HRESULT DSOUND_PrimaryPlay(DirectSoundDevice *device) HRESULT DSOUND_PrimaryPlay(DirectSoundDevice *device)
{ {
HRESULT err = DS_OK; HRESULT hr;
TRACE("(%p)\n", device); TRACE("(%p)\n", device);
err = mmErr(waveOutRestart(device->hwo)); hr = IAudioClient_Start(device->client);
if (err != DS_OK) if(FAILED(hr)){
WARN("waveOutRestart failed\n"); WARN("Start failed: %08x\n", hr);
return hr;
}
return err; return DS_OK;
} }
HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device) HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device)
{ {
HRESULT err = DS_OK; HRESULT hr;
TRACE("(%p)\n", device);
/* don't call the wave system with the lock set */
LeaveCriticalSection(&(device->mixlock));
err = mmErr(waveOutPause(device->hwo)); TRACE("(%p)\n", device);
EnterCriticalSection(&(device->mixlock));
if (err != DS_OK) hr = IAudioClient_Stop(device->client);
WARN("waveOutPause failed\n"); if(FAILED(hr)){
WARN("Stop failed: %08x\n", hr);
return hr;
}
return err; return DS_OK;
} }
HRESULT DSOUND_PrimaryGetPosition(DirectSoundDevice *device, LPDWORD playpos, LPDWORD writepos) HRESULT DSOUND_PrimaryGetPosition(DirectSoundDevice *device, LPDWORD playpos, LPDWORD writepos)
...@@ -331,15 +345,15 @@ LPWAVEFORMATEX DSOUND_CopyFormat(LPCWAVEFORMATEX wfex) ...@@ -331,15 +345,15 @@ LPWAVEFORMATEX DSOUND_CopyFormat(LPCWAVEFORMATEX wfex)
return pwfx; return pwfx;
} }
HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex) HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX passed_fmt)
{ {
HRESULT err = DSERR_BUFFERLOST; HRESULT err = DSERR_BUFFERLOST;
int i; int i;
DWORD nSamplesPerSec, bpp, chans; WAVEFORMATEX *old_fmt;
LPWAVEFORMATEX oldpwfx; WAVEFORMATEXTENSIBLE *fmtex;
BOOL forced = device->priolevel == DSSCL_WRITEPRIMARY; BOOL forced = (device->priolevel == DSSCL_WRITEPRIMARY);
TRACE("(%p,%p)\n", device, wfex); TRACE("(%p,%p)\n", device, passed_fmt);
if (device->priolevel == DSSCL_NORMAL) { if (device->priolevel == DSSCL_NORMAL) {
WARN("failed priority check!\n"); WARN("failed priority check!\n");
...@@ -347,29 +361,26 @@ HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex) ...@@ -347,29 +361,26 @@ HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex)
} }
/* Let's be pedantic! */ /* Let's be pedantic! */
if (wfex == NULL) { if (passed_fmt == NULL) {
WARN("invalid parameter: wfex==NULL!\n"); WARN("invalid parameter: passed_fmt==NULL!\n");
return DSERR_INVALIDPARAM; return DSERR_INVALIDPARAM;
} }
TRACE("(formattag=0x%04x,chans=%d,samplerate=%d," TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
"bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n", "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec, passed_fmt->wFormatTag, passed_fmt->nChannels, passed_fmt->nSamplesPerSec,
wfex->nAvgBytesPerSec, wfex->nBlockAlign, passed_fmt->nAvgBytesPerSec, passed_fmt->nBlockAlign,
wfex->wBitsPerSample, wfex->cbSize); passed_fmt->wBitsPerSample, passed_fmt->cbSize);
/* **** */ /* **** */
RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE); RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
EnterCriticalSection(&(device->mixlock)); EnterCriticalSection(&(device->mixlock));
nSamplesPerSec = device->pwfx->nSamplesPerSec; old_fmt = device->pwfx;
bpp = device->pwfx->wBitsPerSample; device->pwfx = DSOUND_CopyFormat(passed_fmt);
chans = device->pwfx->nChannels; fmtex = (WAVEFORMATEXTENSIBLE *)device->pwfx;
oldpwfx = device->pwfx;
device->pwfx = DSOUND_CopyFormat(wfex);
if (device->pwfx == NULL) { if (device->pwfx == NULL) {
device->pwfx = oldpwfx; device->pwfx = old_fmt;
oldpwfx = NULL; old_fmt = NULL;
err = DSERR_OUTOFMEMORY; err = DSERR_OUTOFMEMORY;
goto done; goto done;
} }
...@@ -377,21 +388,97 @@ HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex) ...@@ -377,21 +388,97 @@ HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex)
DSOUND_PrimaryClose(device); DSOUND_PrimaryClose(device);
err = DSOUND_ReopenDevice(device, FALSE); err = DSOUND_ReopenDevice(device, FALSE);
if (FAILED(err)) if(SUCCEEDED(err))
{ goto opened;
WARN("DSOUND_ReopenDevice failed: %08x\n", err);
goto done; /* 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); err = DSOUND_PrimaryOpen(device);
if (err != DS_OK) { if (err != DS_OK) {
WARN("DSOUND_PrimaryOpen failed\n"); WARN("DSOUND_PrimaryOpen failed\n");
goto done; 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); DSOUND_PrimaryClose(device);
device->pwfx->nSamplesPerSec = wfex->nSamplesPerSec; device->pwfx->nSamplesPerSec = passed_fmt->nSamplesPerSec;
err = DSOUND_ReopenDevice(device, TRUE); err = DSOUND_ReopenDevice(device, TRUE);
if (FAILED(err)) if (FAILED(err))
WARN("DSOUND_ReopenDevice(2) failed: %08x\n", err); WARN("DSOUND_ReopenDevice(2) failed: %08x\n", err);
...@@ -405,7 +492,9 @@ HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex) ...@@ -405,7 +492,9 @@ HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex)
device->mixfunction = mixfunctions[device->pwfx->wBitsPerSample/8 - 1]; device->mixfunction = mixfunctions[device->pwfx->wBitsPerSample/8 - 1];
device->normfunction = normfunctions[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; IDirectSoundBufferImpl** dsb = device->buffers;
for (i = 0; i < device->nrofbuffers; i++, dsb++) { for (i = 0; i < device->nrofbuffers; i++, dsb++) {
/* **** */ /* **** */
...@@ -426,7 +515,7 @@ done: ...@@ -426,7 +515,7 @@ done:
RtlReleaseResource(&(device->buffer_list_lock)); RtlReleaseResource(&(device->buffer_list_lock));
/* **** */ /* **** */
HeapFree(GetProcessHeap(), 0, oldpwfx); HeapFree(GetProcessHeap(), 0, old_fmt);
return err; return err;
} }
...@@ -455,8 +544,9 @@ static HRESULT WINAPI PrimaryBufferImpl_SetVolume( ...@@ -455,8 +544,9 @@ static HRESULT WINAPI PrimaryBufferImpl_SetVolume(
) { ) {
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface); IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
DirectSoundDevice *device = This->device; DirectSoundDevice *device = This->device;
DWORD ampfactors; HRESULT hr;
HRESULT hres = DS_OK; float lvol, rvol;
TRACE("(%p,%d)\n", iface, vol); TRACE("(%p,%d)\n", iface, vol);
if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) { if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
...@@ -470,23 +560,55 @@ static HRESULT WINAPI PrimaryBufferImpl_SetVolume( ...@@ -470,23 +560,55 @@ 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, &ampfactors);
device->volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff;
device->volpan.dwTotalRightAmpFactor=ampfactors >> 16;
DSOUND_AmpFactorToVolPan(&device->volpan); DSOUND_AmpFactorToVolPan(&device->volpan);
if (vol != device->volpan.lVolume) { if (vol != device->volpan.lVolume) {
device->volpan.lVolume=vol; device->volpan.lVolume=vol;
DSOUND_RecalcVolPan(&device->volpan); DSOUND_RecalcVolPan(&device->volpan);
ampfactors = (device->volpan.dwTotalLeftAmpFactor & 0xffff) | (device->volpan.dwTotalRightAmpFactor << 16); lvol = (float)((DWORD)(device->volpan.dwTotalLeftAmpFactor & 0xFFFF) / (float)0xFFFF);
waveOutSetVolume(device->hwo, ampfactors); 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_GetVolume( static HRESULT WINAPI PrimaryBufferImpl_GetVolume(
...@@ -494,7 +616,8 @@ static HRESULT WINAPI PrimaryBufferImpl_GetVolume( ...@@ -494,7 +616,8 @@ static HRESULT WINAPI PrimaryBufferImpl_GetVolume(
) { ) {
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface); IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
DirectSoundDevice *device = This->device; DirectSoundDevice *device = This->device;
DWORD ampfactors; float lvol, rvol;
HRESULT hr;
TRACE("(%p,%p)\n", iface, vol); TRACE("(%p,%p)\n", iface, vol);
if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) { if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
...@@ -507,12 +630,33 @@ static HRESULT WINAPI PrimaryBufferImpl_GetVolume( ...@@ -507,12 +630,33 @@ static HRESULT WINAPI PrimaryBufferImpl_GetVolume(
return DSERR_INVALIDPARAM; return DSERR_INVALIDPARAM;
} }
waveOutGetVolume(device->hwo, &ampfactors); EnterCriticalSection(&device->mixlock);
device->volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff;
device->volpan.dwTotalRightAmpFactor=ampfactors >> 16; 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); DSOUND_AmpFactorToVolPan(&device->volpan);
*vol = device->volpan.lVolume; *vol = device->volpan.lVolume;
LeaveCriticalSection(&device->mixlock);
return DS_OK; return DS_OK;
} }
...@@ -778,8 +922,8 @@ static HRESULT WINAPI PrimaryBufferImpl_SetPan( ...@@ -778,8 +922,8 @@ static HRESULT WINAPI PrimaryBufferImpl_SetPan(
) { ) {
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface); IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
DirectSoundDevice *device = This->device; DirectSoundDevice *device = This->device;
DWORD ampfactors; float lvol, rvol;
HRESULT hres = DS_OK; HRESULT hr;
TRACE("(%p,%d)\n", iface, pan); TRACE("(%p,%d)\n", iface, pan);
if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) { if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
...@@ -793,23 +937,56 @@ static HRESULT WINAPI PrimaryBufferImpl_SetPan( ...@@ -793,23 +937,56 @@ 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, &ampfactors);
device->volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff;
device->volpan.dwTotalRightAmpFactor=ampfactors >> 16;
DSOUND_AmpFactorToVolPan(&device->volpan); DSOUND_AmpFactorToVolPan(&device->volpan);
if (pan != device->volpan.lPan) { if (pan != device->volpan.lPan) {
device->volpan.lPan=pan; device->volpan.lPan=pan;
DSOUND_RecalcVolPan(&device->volpan); 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;
} }
LeaveCriticalSection(&(device->mixlock)); 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_GetPan( static HRESULT WINAPI PrimaryBufferImpl_GetPan(
...@@ -817,7 +994,8 @@ static HRESULT WINAPI PrimaryBufferImpl_GetPan( ...@@ -817,7 +994,8 @@ static HRESULT WINAPI PrimaryBufferImpl_GetPan(
) { ) {
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface); IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
DirectSoundDevice *device = This->device; DirectSoundDevice *device = This->device;
DWORD ampfactors; float lvol, rvol;
HRESULT hr;
TRACE("(%p,%p)\n", iface, pan); TRACE("(%p,%p)\n", iface, pan);
if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) { if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
...@@ -830,11 +1008,33 @@ static HRESULT WINAPI PrimaryBufferImpl_GetPan( ...@@ -830,11 +1008,33 @@ static HRESULT WINAPI PrimaryBufferImpl_GetPan(
return DSERR_INVALIDPARAM; return DSERR_INVALIDPARAM;
} }
waveOutGetVolume(device->hwo, &ampfactors); EnterCriticalSection(&device->mixlock);
device->volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff;
device->volpan.dwTotalRightAmpFactor=ampfactors >> 16; 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); DSOUND_AmpFactorToVolPan(&device->volpan);
*pan = device->volpan.lPan; *pan = device->volpan.lPan;
LeaveCriticalSection(&device->mixlock);
return DS_OK; return DS_OK;
} }
......
...@@ -71,7 +71,7 @@ START_TEST(dependency) ...@@ -71,7 +71,7 @@ START_TEST(dependency)
ok(!GetModuleHandle("dsound.dll"), "dsound.dll was already loaded!\n"); ok(!GetModuleHandle("dsound.dll"), "dsound.dll was already loaded!\n");
hr = IMMDevice_Activate(dev, &IID_IDirectSound8, CLSCTX_INPROC_SERVER, NULL, (void**)&ds8); 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) if (hr == S_OK)
{ {
ok(GetModuleHandle("dsound.dll") != NULL, "dsound.dll not loaded!\n"); ok(GetModuleHandle("dsound.dll") != NULL, "dsound.dll not loaded!\n");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment