winmm: Rearrange device mapping when a new default device is chosen.

This commit is contained in:
Andrew Eikum 2012-12-26 08:40:03 -06:00 committed by Alexandre Julliard
parent 99065bb65f
commit 4ab4bc5d09
1 changed files with 142 additions and 17 deletions

View File

@ -278,6 +278,15 @@ static void WINMM_InitDevice(WINMM_Device *device,
device->parent = parent;
}
static inline WINMM_MMDevice *read_map(WINMM_MMDevice **map, UINT index)
{
WINMM_MMDevice *ret;
EnterCriticalSection(&g_devthread_lock);
ret = map[index];
LeaveCriticalSection(&g_devthread_lock);
return ret;
}
/* finds the first unused Device, marks it as "open", and returns
* a pointer to the device
*
@ -290,9 +299,9 @@ static WINMM_Device *WINMM_FindUnusedDevice(BOOL is_out, UINT mmdevice_index)
UINT i;
if(is_out)
mmdevice = g_out_map[mmdevice_index];
mmdevice = read_map(g_out_map, mmdevice_index);
else
mmdevice = g_in_map[mmdevice_index];
mmdevice = read_map(g_in_map, mmdevice_index);
EnterCriticalSection(&mmdevice->lock);
for(i = 0; i < MAX_DEVICES; ++i){
@ -629,6 +638,112 @@ static HRESULT WINMM_EnumDevices(WINMM_MMDevice **devices,
return S_OK;
}
static HRESULT WINAPI notif_QueryInterface(IMMNotificationClient *iface,
const GUID *riid, void **obj)
{
ERR("Unexpected QueryInterface call: %s\n", wine_dbgstr_guid(riid));
return E_NOINTERFACE;
}
static ULONG WINAPI notif_AddRef(IMMNotificationClient *iface)
{
return 2;
}
static ULONG WINAPI notif_Release(IMMNotificationClient *iface)
{
return 1;
}
static HRESULT WINAPI notif_OnDeviceStateChanged(IMMNotificationClient *iface,
const WCHAR *device_id, DWORD new_state)
{
TRACE("Ignoring OnDeviceStateChanged callback\n");
return S_OK;
}
static HRESULT WINAPI notif_OnDeviceAdded(IMMNotificationClient *iface,
const WCHAR *device_id)
{
TRACE("Ignoring OnDeviceAdded callback\n");
return S_OK;
}
static HRESULT WINAPI notif_OnDeviceRemoved(IMMNotificationClient *iface,
const WCHAR *device_id)
{
TRACE("Ignoring OnDeviceRemoved callback\n");
return S_OK;
}
static HRESULT WINAPI notif_OnDefaultDeviceChanged(IMMNotificationClient *iface,
EDataFlow flow, ERole role, const WCHAR *device_id)
{
WINMM_MMDevice ***map;
WINMM_MMDevice *prev;
UINT count, i;
TRACE("%u %u %s\n", flow, role, wine_dbgstr_w(device_id));
if(role != eConsole)
return S_OK;
EnterCriticalSection(&g_devthread_lock);
if(flow == eRender){
map = &g_out_map;
count = g_outmmdevices_count;
}else{
map = &g_in_map;
count = g_inmmdevices_count;
}
prev = (*map)[0];
for(i = 0; i < count; ++i){
WINMM_MMDevice *tmp;
if(!lstrcmpW((*map)[i]->dev_id, device_id)){
(*map)[0] = (*map)[i];
(*map)[i] = prev;
LeaveCriticalSection(&g_devthread_lock);
return S_OK;
}
tmp = (*map)[i];
(*map)[i] = prev;
prev = tmp;
}
WARN("Couldn't find new default device! Rearranged map for no reason.\n");
(*map)[0] = prev;
LeaveCriticalSection(&g_devthread_lock);
return S_OK;
}
static HRESULT WINAPI notif_OnPropertyValueChanged(IMMNotificationClient *iface,
const WCHAR *device_id, const PROPERTYKEY key)
{
TRACE("Ignoring OnPropertyValueChanged callback\n");
return S_OK;
}
static IMMNotificationClientVtbl g_notif_vtbl = {
notif_QueryInterface,
notif_AddRef,
notif_Release,
notif_OnDeviceStateChanged,
notif_OnDeviceAdded,
notif_OnDeviceRemoved,
notif_OnDefaultDeviceChanged,
notif_OnPropertyValueChanged
};
static IMMNotificationClient g_notif = { &g_notif_vtbl };
static HRESULT WINMM_InitMMDevices(void)
{
HRESULT hr, init_hr;
@ -644,6 +759,10 @@ static HRESULT WINMM_InitMMDevices(void)
if(FAILED(hr))
goto exit;
hr = IMMDeviceEnumerator_RegisterEndpointNotificationCallback(devenum, &g_notif);
if(FAILED(hr))
WARN("RegisterEndpointNotificationCallback failed: %08x\n", hr);
hr = WINMM_EnumDevices(&g_out_mmdevices, &g_out_map, &g_outmmdevices_count,
eRender, devenum);
if(FAILED(hr)){
@ -1087,7 +1206,7 @@ static LRESULT WOD_Open(WINMM_OpenInfo *info)
if(info->req_device >= g_outmmdevices_count)
return MMSYSERR_BADDEVICEID;
mmdevice = g_out_map[info->req_device];
mmdevice = read_map(g_out_map, info->req_device);
if(!mmdevice->out_caps.szPname[0])
return MMSYSERR_NOTENABLED;
@ -1160,7 +1279,7 @@ static LRESULT WID_Open(WINMM_OpenInfo *info)
if(info->req_device >= g_inmmdevices_count)
return MMSYSERR_BADDEVICEID;
mmdevice = g_in_map[info->req_device];
mmdevice = read_map(g_in_map, info->req_device);
if(!mmdevice->in_caps.szPname[0])
return MMSYSERR_NOTENABLED;
@ -1900,10 +2019,10 @@ static WINMM_MMDevice *WINMM_GetMixerMMDevice(HMIXEROBJ hmix, DWORD flags,
case MIXER_OBJECTF_MIXER: /* == 0 */
*out = HandleToULong(hmix);
if(*out < g_outmmdevices_count)
return g_out_map[*out];
return read_map(g_out_map, *out);
if(*out - g_outmmdevices_count < g_inmmdevices_count){
*out -= g_outmmdevices_count;
return g_in_map[*out];
return read_map(g_in_map, *out);
}
/* fall through -- if it's not a valid mixer device, then
* it could be a valid mixer handle. windows seems to do
@ -1916,17 +2035,17 @@ static WINMM_MMDevice *WINMM_GetMixerMMDevice(HMIXEROBJ hmix, DWORD flags,
(!is_out && *out >= g_inmmdevices_count))
return NULL;
if(is_out)
return g_out_map[*out];
return g_in_map[*out];
return read_map(g_out_map, *out);
return read_map(g_in_map, *out);
case MIXER_OBJECTF_WAVEOUT:
*out = HandleToULong(hmix);
if(*out < g_outmmdevices_count)
return g_out_map[*out];
return read_map(g_out_map, *out);
return NULL;
case MIXER_OBJECTF_WAVEIN:
*out = HandleToULong(hmix);
if(*out < g_inmmdevices_count)
return g_in_map[*out];
return read_map(g_in_map, *out);
return NULL;
}
@ -2440,7 +2559,7 @@ UINT WINAPI waveOutGetDevCapsW(UINT_PTR uDeviceID, LPWAVEOUTCAPSW lpCaps,
if(uDeviceID >= g_outmmdevices_count)
return MMSYSERR_BADDEVICEID;
caps = &g_out_map[uDeviceID]->out_caps;
caps = &read_map(g_out_map, uDeviceID)->out_caps;
}
memcpy(lpCaps, caps, min(uSize, sizeof(*lpCaps)));
@ -2939,7 +3058,9 @@ static UINT WINMM_QueryInstanceIDSize(UINT device, DWORD_PTR *len, BOOL is_out)
if(device >= count)
return MMSYSERR_INVALHANDLE;
EnterCriticalSection(&g_devthread_lock);
*len = (lstrlenW(devices[device]->dev_id) + 1) * sizeof(WCHAR);
LeaveCriticalSection(&g_devthread_lock);
return MMSYSERR_NOERROR;
}
@ -2963,11 +3084,15 @@ static UINT WINMM_QueryInstanceID(UINT device, WCHAR *str, DWORD_PTR len,
if(device >= count)
return MMSYSERR_INVALHANDLE;
EnterCriticalSection(&g_devthread_lock);
id_len = (lstrlenW(devices[device]->dev_id) + 1) * sizeof(WCHAR);
if(len < id_len)
if(len < id_len){
LeaveCriticalSection(&g_devthread_lock);
return MMSYSERR_ERROR;
}
memcpy(str, devices[device]->dev_id, id_len);
LeaveCriticalSection(&g_devthread_lock);
return MMSYSERR_NOERROR;
}
@ -3082,7 +3207,7 @@ UINT WINAPI waveInGetDevCapsW(UINT_PTR uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSi
if(uDeviceID >= g_inmmdevices_count)
return MMSYSERR_BADDEVICEID;
caps = &g_in_map[uDeviceID]->in_caps;
caps = &read_map(g_in_map, uDeviceID)->in_caps;
}
memcpy(lpCaps, caps, min(uSize, sizeof(*lpCaps)));
@ -3495,10 +3620,10 @@ UINT WINAPI mixerGetDevCapsW(UINT_PTR uDeviceID, LPMIXERCAPSW lpCaps, UINT uSize
return MMSYSERR_BADDEVICEID;
if(uDeviceID < g_outmmdevices_count){
mmdevice = g_out_map[uDeviceID];
mmdevice = read_map(g_out_map, uDeviceID);
memcpy(caps.szPname, mmdevice->out_caps.szPname, sizeof(caps.szPname));
}else{
mmdevice = g_in_map[uDeviceID - g_outmmdevices_count];
mmdevice = read_map(g_in_map, uDeviceID - g_outmmdevices_count);
memcpy(caps.szPname, mmdevice->in_caps.szPname, sizeof(caps.szPname));
}
@ -3541,11 +3666,11 @@ UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback,
return MMSYSERR_BADDEVICEID;
if(uDeviceID < g_outmmdevices_count){
mmdevice = g_out_map[uDeviceID];
mmdevice = read_map(g_out_map, uDeviceID);
*lphMix = (HMIXER)WINMM_MakeHWAVE(uDeviceID, TRUE,
mmdevice->mixer_count);
}else{
mmdevice = g_in_map[uDeviceID - g_outmmdevices_count];
mmdevice = read_map(g_in_map, uDeviceID - g_outmmdevices_count);
*lphMix = (HMIXER)WINMM_MakeHWAVE(uDeviceID - g_outmmdevices_count,
FALSE, mmdevice->mixer_count);
}