From 38d80c7310ccb3a86ad833c9e2d7a76c8252528b Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Mon, 6 Jun 2011 08:49:34 -0500 Subject: [PATCH] winecoreaudio.drv: Partially implement IAudioSessionManager2. --- dlls/winecoreaudio.drv/mmdevdrv.c | 323 ++++++++++++++---- dlls/winecoreaudio.drv/winecoreaudio.drv.spec | 1 + 2 files changed, 255 insertions(+), 69 deletions(-) diff --git a/dlls/winecoreaudio.drv/mmdevdrv.c b/dlls/winecoreaudio.drv/mmdevdrv.c index 6ad6b90e897..9075aa89ac0 100644 --- a/dlls/winecoreaudio.drv/mmdevdrv.c +++ b/dlls/winecoreaudio.drv/mmdevdrv.c @@ -158,6 +158,15 @@ static const IAudioClockVtbl AudioClock_Vtbl; static const IAudioClock2Vtbl AudioClock2_Vtbl; static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl; static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl; +static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl; + +typedef struct _SessionMgr { + IAudioSessionManager2 IAudioSessionManager2_iface; + + LONG ref; + + EDataFlow flow; +} SessionMgr; static HANDLE g_timer_q; @@ -214,6 +223,11 @@ static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface) return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface); } +static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface) +{ + return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface); +} + BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved) { if(reason == DLL_PROCESS_ATTACH){ @@ -489,12 +503,6 @@ static ULONG WINAPI AudioClient_Release(IAudioClient *iface) if(This->session){ EnterCriticalSection(&g_sessions_lock); list_remove(&This->entry); - if(list_empty(&This->session->clients)){ - list_remove(&This->session->entry); - DeleteCriticalSection(&This->session->lock); - HeapFree(GetProcessHeap(), 0, This->session->channel_vols); - HeapFree(GetProcessHeap(), 0, This->session); - } LeaveCriticalSection(&g_sessions_lock); } HeapFree(GetProcessHeap(), 0, This->vols); @@ -709,8 +717,21 @@ static HRESULT ca_setup_aqueue(AudioDeviceID did, EDataFlow flow, return S_OK; } +static void session_init_vols(AudioSession *session, UINT channels) +{ + session->channel_vols = HeapAlloc(GetProcessHeap(), 0, + sizeof(float) * channels); + if(!session->channel_vols) + return; + + session->channel_count = channels; + + for(; channels > 0; --channels) + session->channel_vols[channels - 1] = 1.f; +} + static AudioSession *create_session(const GUID *guid, EDataFlow flow, - int num_channels) + UINT num_channels) { AudioSession *ret; @@ -728,22 +749,52 @@ static AudioSession *create_session(const GUID *guid, EDataFlow flow, InitializeCriticalSection(&ret->lock); - ret->channel_count = num_channels; - ret->channel_vols = HeapAlloc(GetProcessHeap(), 0, - sizeof(float) * num_channels); - if(!ret->channel_vols){ - HeapFree(GetProcessHeap(), 0, ret); - return NULL; - } - - for(; num_channels > 0; --num_channels) - ret->channel_vols[num_channels - 1] = 1.f; + if(num_channels > 0) + session_init_vols(ret, num_channels); ret->master_vol = 1.f; return ret; } +/* if channels == 0, then this will return or create a session with + * matching dataflow and GUID. otherwise, channels must also match */ +static HRESULT get_audio_session(const GUID *sessionguid, + EDataFlow flow, UINT channels, AudioSession **out) +{ + AudioSession *session; + + if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){ + *out = create_session(&GUID_NULL, flow, channels); + if(!*out) + return E_OUTOFMEMORY; + + return S_OK; + } + + *out = NULL; + LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){ + if(IsEqualGUID(sessionguid, &session->guid) && + session->dataflow == flow){ + if(session->channel_count > 0){ + if(channels > 0 && session->channel_count != channels) + return E_INVALIDARG; + }else if(channels > 0) + session_init_vols(session, channels); + *out = session; + break; + } + } + + if(!*out){ + *out = create_session(sessionguid, flow, channels); + if(!*out) + return E_OUTOFMEMORY; + } + + return S_OK; +} + static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface, AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration, REFERENCE_TIME period, const WAVEFORMATEX *fmt, @@ -863,56 +914,18 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface, EnterCriticalSection(&g_sessions_lock); - if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){ - This->session = create_session(&GUID_NULL, This->dataflow, - fmt->nChannels); - if(!This->session){ - LeaveCriticalSection(&g_sessions_lock); - AudioQueueDispose(This->aqueue, 1); - This->aqueue = NULL; - CoTaskMemFree(This->fmt); - This->fmt = NULL; - HeapFree(GetProcessHeap(), 0, This->vols); - This->vols = NULL; - OSSpinLockUnlock(&This->lock); - return E_OUTOFMEMORY; - } - }else{ - AudioSession *session; - - LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){ - if(IsEqualGUID(sessionguid, &session->guid) && - This->dataflow == session->dataflow){ - if(session->channel_count != fmt->nChannels){ - LeaveCriticalSection(&g_sessions_lock); - AudioQueueDispose(This->aqueue, 1); - This->aqueue = NULL; - CoTaskMemFree(This->fmt); - This->fmt = NULL; - HeapFree(GetProcessHeap(), 0, This->vols); - This->vols = NULL; - OSSpinLockUnlock(&This->lock); - return E_INVALIDARG; - } - This->session = session; - } - } - - if(!This->session){ - This->session = create_session(sessionguid, This->dataflow, - fmt->nChannels); - if(!This->session){ - LeaveCriticalSection(&g_sessions_lock); - AudioQueueDispose(This->aqueue, 1); - This->aqueue = NULL; - CoTaskMemFree(This->fmt); - This->fmt = NULL; - HeapFree(GetProcessHeap(), 0, This->vols); - This->vols = NULL; - OSSpinLockUnlock(&This->lock); - return E_OUTOFMEMORY; - } - } + hr = get_audio_session(sessionguid, This->dataflow, fmt->nChannels, + &This->session); + if(FAILED(hr)){ + LeaveCriticalSection(&g_sessions_lock); + AudioQueueDispose(This->aqueue, 1); + This->aqueue = NULL; + CoTaskMemFree(This->fmt); + This->fmt = NULL; + HeapFree(GetProcessHeap(), 0, This->vols); + This->vols = NULL; + OSSpinLockUnlock(&This->lock); + return E_INVALIDARG; } list_add_tail(&This->session->clients, &This->entry); @@ -2020,8 +2033,10 @@ static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client) ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl; ret->client = client; - ret->session = client->session; - AudioClient_AddRef(&client->IAudioClient_iface); + if(client){ + ret->session = client->session; + AudioClient_AddRef(&client->IAudioClient_iface); + } return ret; } @@ -2748,3 +2763,173 @@ static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl = ChannelAudioVolume_SetAllVolumes, ChannelAudioVolume_GetAllVolumes }; + +HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface, + REFIID riid, void **ppv) +{ + TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); + + if(!ppv) + return E_POINTER; + *ppv = NULL; + + if(IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IAudioSessionManager) || + IsEqualIID(riid, &IID_IAudioSessionManager2)) + *ppv = iface; + if(*ppv){ + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; + } + + WARN("Unknown interface %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface) +{ + SessionMgr *This = impl_from_IAudioSessionManager2(iface); + ULONG ref; + ref = InterlockedIncrement(&This->ref); + TRACE("(%p) Refcount now %u\n", This, ref); + return ref; +} + +ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface) +{ + SessionMgr *This = impl_from_IAudioSessionManager2(iface); + ULONG ref; + ref = InterlockedDecrement(&This->ref); + TRACE("(%p) Refcount now %u\n", This, ref); + if(!ref) + HeapFree(GetProcessHeap(), 0, This); + return ref; +} + +HRESULT WINAPI AudioSessionManager_GetAudioSessionControl( + IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags, + IAudioSessionControl **out) +{ + SessionMgr *This = impl_from_IAudioSessionManager2(iface); + AudioSession *session; + AudioSessionWrapper *wrapper; + HRESULT hr; + + TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid), + flags, out); + + hr = get_audio_session(session_guid, This->flow, 0, &session); + if(FAILED(hr)) + return hr; + + wrapper = AudioSessionWrapper_Create(NULL); + if(!wrapper) + return E_OUTOFMEMORY; + + wrapper->session = session; + + *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface; + + return S_OK; +} + +HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume( + IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags, + ISimpleAudioVolume **out) +{ + SessionMgr *This = impl_from_IAudioSessionManager2(iface); + AudioSession *session; + AudioSessionWrapper *wrapper; + HRESULT hr; + + TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid), + flags, out); + + hr = get_audio_session(session_guid, This->flow, 0, &session); + if(FAILED(hr)) + return hr; + + wrapper = AudioSessionWrapper_Create(NULL); + if(!wrapper) + return E_OUTOFMEMORY; + + wrapper->session = session; + + *out = &wrapper->ISimpleAudioVolume_iface; + + return S_OK; +} + +HRESULT WINAPI AudioSessionManager_GetSessionEnumerator( + IAudioSessionManager2 *iface, IAudioSessionEnumerator **out) +{ + SessionMgr *This = impl_from_IAudioSessionManager2(iface); + FIXME("(%p)->(%p) - stub\n", This, out); + return E_NOTIMPL; +} + +HRESULT WINAPI AudioSessionManager_RegisterSessionNotification( + IAudioSessionManager2 *iface, IAudioSessionNotification *notification) +{ + SessionMgr *This = impl_from_IAudioSessionManager2(iface); + FIXME("(%p)->(%p) - stub\n", This, notification); + return E_NOTIMPL; +} + +HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification( + IAudioSessionManager2 *iface, IAudioSessionNotification *notification) +{ + SessionMgr *This = impl_from_IAudioSessionManager2(iface); + FIXME("(%p)->(%p) - stub\n", This, notification); + return E_NOTIMPL; +} + +HRESULT WINAPI AudioSessionManager_RegisterDuckNotification( + IAudioSessionManager2 *iface, const WCHAR *session_id, + IAudioVolumeDuckNotification *notification) +{ + SessionMgr *This = impl_from_IAudioSessionManager2(iface); + FIXME("(%p)->(%p) - stub\n", This, notification); + return E_NOTIMPL; +} + +HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification( + IAudioSessionManager2 *iface, + IAudioVolumeDuckNotification *notification) +{ + SessionMgr *This = impl_from_IAudioSessionManager2(iface); + FIXME("(%p)->(%p) - stub\n", This, notification); + return E_NOTIMPL; +} + +static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl = +{ + AudioSessionManager_QueryInterface, + AudioSessionManager_AddRef, + AudioSessionManager_Release, + AudioSessionManager_GetAudioSessionControl, + AudioSessionManager_GetSimpleAudioVolume, + AudioSessionManager_GetSessionEnumerator, + AudioSessionManager_RegisterSessionNotification, + AudioSessionManager_UnregisterSessionNotification, + AudioSessionManager_RegisterDuckNotification, + AudioSessionManager_UnregisterDuckNotification +}; + +HRESULT WINAPI AUDDRV_GetAudioSessionManager(EDataFlow dataflow, + IAudioSessionManager2 **out) +{ + SessionMgr *This; + + This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr)); + if(!*out) + return E_OUTOFMEMORY; + + This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl; + This->flow = dataflow; + This->ref = 1; + + *out = &This->IAudioSessionManager2_iface; + + return S_OK; +} diff --git a/dlls/winecoreaudio.drv/winecoreaudio.drv.spec b/dlls/winecoreaudio.drv/winecoreaudio.drv.spec index 944bffb49bb..2f27c8a8616 100644 --- a/dlls/winecoreaudio.drv/winecoreaudio.drv.spec +++ b/dlls/winecoreaudio.drv/winecoreaudio.drv.spec @@ -9,3 +9,4 @@ # MMDevAPI driver functions @ stdcall -private GetEndpointIDs(long ptr ptr ptr) AUDDRV_GetEndpointIDs @ stdcall -private GetAudioEndpoint(str long ptr) AUDDRV_GetAudioEndpoint +@ stdcall -private GetAudioSessionManager(long ptr) AUDDRV_GetAudioSessionManager