From 4a95e7b0c93167ce808db629f5d0a786cc7f228e Mon Sep 17 00:00:00 2001
From: Andrew Eikum <aeikum@codeweavers.com>
Date: Mon, 2 May 2011 08:21:49 -0500
Subject: [PATCH] wineoss.drv: Implement IAudioSessionControl::GetState.

---
 dlls/wineoss.drv/audio.c    |   5 +-
 dlls/wineoss.drv/mmdevdrv.c | 234 ++++++++++++++++++++++++++++++------
 2 files changed, 202 insertions(+), 37 deletions(-)

diff --git a/dlls/wineoss.drv/audio.c b/dlls/wineoss.drv/audio.c
index 174eca56933..eb3dc1e717a 100644
--- a/dlls/wineoss.drv/audio.c
+++ b/dlls/wineoss.drv/audio.c
@@ -76,10 +76,11 @@
 #include "mmreg.h"
 #include "dsound.h"
 #include "ks.h"
-#include "ksmedia.h"
+#include "wine/debug.h"
+
 #include "initguid.h"
+#include "ksmedia.h"
 #include "dsdriver.h"
-#include "wine/debug.h"
 
 #include "audio.h"
 
diff --git a/dlls/wineoss.drv/mmdevdrv.c b/dlls/wineoss.drv/mmdevdrv.c
index 278b1b3bf13..c6baee98eb6 100644
--- a/dlls/wineoss.drv/mmdevdrv.c
+++ b/dlls/wineoss.drv/mmdevdrv.c
@@ -18,7 +18,6 @@
 
 #define NONAMELESSUNION
 #define COBJMACROS
-#define INITGUID
 #include "config.h"
 
 #include <stdarg.h>
@@ -36,9 +35,11 @@
 #include "devpkey.h"
 #include "dshow.h"
 #include "dsound.h"
-#include "audioclient.h"
 #include "endpointvolume.h"
+
+#include "initguid.h"
 #include "audiopolicy.h"
+#include "audioclient.h"
 
 #include <errno.h>
 #include <limits.h>
@@ -62,14 +63,36 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(oss);
 
+#define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
+
 static const REFERENCE_TIME DefaultPeriod = 200000;
 static const REFERENCE_TIME MinimumPeriod = 100000;
 
-typedef struct ACImpl {
+struct ACImpl;
+typedef struct ACImpl ACImpl;
+
+typedef struct _AudioSession {
+    GUID guid;
+    struct list clients;
+
+    EDataFlow dataflow;
+
+    struct list entry;
+} AudioSession;
+
+typedef struct _AudioSessionWrapper {
+    IAudioSessionControl2 IAudioSessionControl2_iface;
+
+    LONG ref;
+
+    ACImpl *client;
+    AudioSession *session;
+} AudioSessionWrapper;
+
+struct ACImpl {
     IAudioClient IAudioClient_iface;
     IAudioRenderClient IAudioRenderClient_iface;
     IAudioCaptureClient IAudioCaptureClient_iface;
-    IAudioSessionControl2 IAudioSessionControl2_iface;
     ISimpleAudioVolume ISimpleAudioVolume_iface;
     IAudioClock IAudioClock_iface;
     IAudioClock2 IAudioClock2_iface;
@@ -98,7 +121,12 @@ typedef struct ACImpl {
     HANDLE timer;
 
     CRITICAL_SECTION lock;
-} ACImpl;
+
+    AudioSession *session;
+    AudioSessionWrapper *session_wrapper;
+
+    struct list entry;
+};
 
 enum BufferStates {
     NOT_LOCKED = 0,
@@ -108,6 +136,11 @@ enum BufferStates {
 
 static HANDLE g_timer_q;
 
+static CRITICAL_SECTION g_sessions_lock;
+static struct list g_sessions = LIST_INIT(g_sessions);
+
+static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
+
 static const IAudioClientVtbl AudioClient_Vtbl;
 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
@@ -131,9 +164,9 @@ static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
     return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
 }
 
-static inline ACImpl *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
+static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
 {
-    return CONTAINING_RECORD(iface, ACImpl, IAudioSessionControl2_iface);
+    return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
 }
 
 static inline ACImpl *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
@@ -157,6 +190,8 @@ BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
         g_timer_q = CreateTimerQueue();
         if(!g_timer_q)
             return FALSE;
+
+        InitializeCriticalSection(&g_sessions_lock);
     }
 
     return TRUE;
@@ -325,7 +360,6 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(char *devnode, IMMDevice *dev,
     This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
     This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
     This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
-    This->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
     This->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
     This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
     This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
@@ -380,6 +414,15 @@ static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
         IMMDevice_Release(This->parent);
         DeleteCriticalSection(&This->lock);
         close(This->fd);
+        if(This->initted){
+            EnterCriticalSection(&g_sessions_lock);
+            list_remove(&This->entry);
+            if(list_empty(&This->session->clients)){
+                list_remove(&This->session->entry);
+                HeapFree(GetProcessHeap(), 0, This->session);
+            }
+            LeaveCriticalSection(&g_sessions_lock);
+        }
         HeapFree(GetProcessHeap(), 0, This->local_buffer);
         HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
         CoTaskMemFree(This->fmt);
@@ -577,6 +620,25 @@ static HRESULT setup_oss_device(ACImpl *This, const WAVEFORMATEX *fmt,
     return ret;
 }
 
+static AudioSession *create_session(const GUID *guid, EDataFlow flow)
+{
+    AudioSession *ret;
+
+    ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
+    if(!ret)
+        return NULL;
+
+    memcpy(&ret->guid, guid, sizeof(GUID));
+
+    ret->dataflow = flow;
+
+    list_init(&ret->clients);
+
+    list_add_head(&g_sessions, &ret->entry);
+
+    return ret;
+}
+
 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
         AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
         REFERENCE_TIME period, const WAVEFORMATEX *fmt,
@@ -658,10 +720,44 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
         return E_OUTOFMEMORY;
     }
 
-    This->initted = TRUE;
     This->share = mode;
     This->flags = flags;
 
+    EnterCriticalSection(&g_sessions_lock);
+
+    if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
+        This->session = create_session(&GUID_NULL, This->dataflow);
+        if(!This->session){
+            CoTaskMemFree(This->fmt);
+            This->fmt = NULL;
+            LeaveCriticalSection(&g_sessions_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)
+                This->session = session;
+
+        if(!This->session){
+            This->session = create_session(sessionguid, This->dataflow);
+            if(!This->session){
+                CoTaskMemFree(This->fmt);
+                This->fmt = NULL;
+                LeaveCriticalSection(&g_sessions_lock);
+                return E_OUTOFMEMORY;
+            }
+        }
+    }
+
+    list_add_tail(&This->session->clients, &This->entry);
+
+    LeaveCriticalSection(&g_sessions_lock);
+
+    This->initted = TRUE;
+
     LeaveCriticalSection(&This->lock);
 
     return S_OK;
@@ -1183,18 +1279,28 @@ static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
         return AUDCLNT_E_NOT_INITIALIZED;
     }
 
-    LeaveCriticalSection(&This->lock);
-
     if(IsEqualIID(riid, &IID_IAudioRenderClient)){
-        if(This->dataflow != eRender)
+        if(This->dataflow != eRender){
+            LeaveCriticalSection(&This->lock);
             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
+        }
         *ppv = &This->IAudioRenderClient_iface;
     }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
-        if(This->dataflow != eCapture)
+        if(This->dataflow != eCapture){
+            LeaveCriticalSection(&This->lock);
             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
+        }
         *ppv = &This->IAudioCaptureClient_iface;
     }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
-        *ppv = &This->IAudioSessionControl2_iface;
+        if(!This->session_wrapper){
+            This->session_wrapper = AudioSessionWrapper_Create(This);
+            if(!This->session_wrapper){
+                LeaveCriticalSection(&This->lock);
+                return E_OUTOFMEMORY;
+            }
+        }
+
+        *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
     }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
         *ppv = &This->ISimpleAudioVolume_iface;
     }else if(IsEqualIID(riid, &IID_IAudioClock)){
@@ -1203,9 +1309,12 @@ static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
 
     if(*ppv){
         IUnknown_AddRef((IUnknown*)*ppv);
+        LeaveCriticalSection(&This->lock);
         return S_OK;
     }
 
+    LeaveCriticalSection(&This->lock);
+
     FIXME("stub %s\n", debugstr_guid(riid));
     return E_NOINTERFACE;
 }
@@ -1566,6 +1675,24 @@ static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
     AudioCaptureClient_GetNextPacketSize
 };
 
+static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
+{
+    AudioSessionWrapper *ret;
+
+    ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+            sizeof(AudioSessionWrapper));
+    if(!ret)
+        return NULL;
+
+    ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
+
+    ret->client = client;
+    ret->session = client->session;
+    AudioClient_AddRef(&client->IAudioClient_iface);
+
+    return ret;
+}
+
 static HRESULT WINAPI AudioSessionControl_QueryInterface(
         IAudioSessionControl2 *iface, REFIID riid, void **ppv)
 {
@@ -1590,33 +1717,70 @@ static HRESULT WINAPI AudioSessionControl_QueryInterface(
 
 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
 {
-    ACImpl *This = impl_from_IAudioSessionControl2(iface);
-    return IAudioClient_AddRef(&This->IAudioClient_iface);
+    AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
+    ULONG ref;
+    ref = InterlockedIncrement(&This->ref);
+    TRACE("(%p) Refcount now %u\n", This, ref);
+    return ref;
 }
 
 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
 {
-    ACImpl *This = impl_from_IAudioSessionControl2(iface);
-    return IAudioClient_Release(&This->IAudioClient_iface);
+    AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
+    ULONG ref;
+    ref = InterlockedDecrement(&This->ref);
+    TRACE("(%p) Refcount now %u\n", This, ref);
+    if(!ref){
+        EnterCriticalSection(&This->client->lock);
+        This->client->session_wrapper = NULL;
+        LeaveCriticalSection(&This->client->lock);
+        AudioClient_Release(&This->client->IAudioClient_iface);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+    return ref;
 }
 
 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
         AudioSessionState *state)
 {
-    ACImpl *This = impl_from_IAudioSessionControl2(iface);
+    AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
+    ACImpl *client;
 
-    FIXME("(%p)->(%p) - stub\n", This, state);
+    TRACE("(%p)->(%p)\n", This, state);
 
     if(!state)
-        return E_POINTER;
+        return NULL_PTR_ERR;
 
-    return E_NOTIMPL;
+    EnterCriticalSection(&g_sessions_lock);
+
+    if(list_empty(&This->session->clients)){
+        *state = AudioSessionStateExpired;
+        LeaveCriticalSection(&g_sessions_lock);
+        return S_OK;
+    }
+
+    LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
+        EnterCriticalSection(&client->lock);
+        if(client->playing){
+            *state = AudioSessionStateActive;
+            LeaveCriticalSection(&client->lock);
+            LeaveCriticalSection(&g_sessions_lock);
+            return S_OK;
+        }
+        LeaveCriticalSection(&client->lock);
+    }
+
+    LeaveCriticalSection(&g_sessions_lock);
+
+    *state = AudioSessionStateInactive;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
         IAudioSessionControl2 *iface, WCHAR **name)
 {
-    ACImpl *This = impl_from_IAudioSessionControl2(iface);
+    AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
 
     FIXME("(%p)->(%p) - stub\n", This, name);
 
@@ -1626,7 +1790,7 @@ static HRESULT WINAPI AudioSessionControl_GetDisplayName(
 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
         IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
 {
-    ACImpl *This = impl_from_IAudioSessionControl2(iface);
+    AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
 
     FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
 
@@ -1636,7 +1800,7 @@ static HRESULT WINAPI AudioSessionControl_SetDisplayName(
 static HRESULT WINAPI AudioSessionControl_GetIconPath(
         IAudioSessionControl2 *iface, WCHAR **path)
 {
-    ACImpl *This = impl_from_IAudioSessionControl2(iface);
+    AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
 
     FIXME("(%p)->(%p) - stub\n", This, path);
 
@@ -1646,7 +1810,7 @@ static HRESULT WINAPI AudioSessionControl_GetIconPath(
 static HRESULT WINAPI AudioSessionControl_SetIconPath(
         IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
 {
-    ACImpl *This = impl_from_IAudioSessionControl2(iface);
+    AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
 
     FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
 
@@ -1656,7 +1820,7 @@ static HRESULT WINAPI AudioSessionControl_SetIconPath(
 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
         IAudioSessionControl2 *iface, GUID *group)
 {
-    ACImpl *This = impl_from_IAudioSessionControl2(iface);
+    AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
 
     FIXME("(%p)->(%p) - stub\n", This, group);
 
@@ -1666,7 +1830,7 @@ static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
         IAudioSessionControl2 *iface, GUID *group, const GUID *session)
 {
-    ACImpl *This = impl_from_IAudioSessionControl2(iface);
+    AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
 
     FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
             debugstr_guid(session));
@@ -1677,7 +1841,7 @@ static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
 {
-    ACImpl *This = impl_from_IAudioSessionControl2(iface);
+    AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
 
     FIXME("(%p)->(%p) - stub\n", This, events);
 
@@ -1687,7 +1851,7 @@ static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
 {
-    ACImpl *This = impl_from_IAudioSessionControl2(iface);
+    AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
 
     FIXME("(%p)->(%p) - stub\n", This, events);
 
@@ -1697,7 +1861,7 @@ static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
         IAudioSessionControl2 *iface, WCHAR **id)
 {
-    ACImpl *This = impl_from_IAudioSessionControl2(iface);
+    AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
 
     FIXME("(%p)->(%p) - stub\n", This, id);
 
@@ -1707,7 +1871,7 @@ static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
         IAudioSessionControl2 *iface, WCHAR **id)
 {
-    ACImpl *This = impl_from_IAudioSessionControl2(iface);
+    AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
 
     FIXME("(%p)->(%p) - stub\n", This, id);
 
@@ -1717,7 +1881,7 @@ static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
 static HRESULT WINAPI AudioSessionControl_GetProcessId(
         IAudioSessionControl2 *iface, DWORD *pid)
 {
-    ACImpl *This = impl_from_IAudioSessionControl2(iface);
+    AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
 
     TRACE("(%p)->(%p)\n", This, pid);
 
@@ -1732,7 +1896,7 @@ static HRESULT WINAPI AudioSessionControl_GetProcessId(
 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
         IAudioSessionControl2 *iface)
 {
-    ACImpl *This = impl_from_IAudioSessionControl2(iface);
+    AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
 
     TRACE("(%p)\n", This);
 
@@ -1742,7 +1906,7 @@ static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
         IAudioSessionControl2 *iface, BOOL optout)
 {
-    ACImpl *This = impl_from_IAudioSessionControl2(iface);
+    AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
 
     TRACE("(%p)->(%d)\n", This, optout);
 
-- 
GitLab