winecoreaudio.drv: Implement volume control interfaces.

This commit is contained in:
Andrew Eikum 2011-05-06 10:34:34 -05:00 committed by Alexandre Julliard
parent b9a66b1bc3
commit e8f3d4736a
1 changed files with 521 additions and 26 deletions

View File

@ -79,11 +79,19 @@ typedef struct _AudioSession {
EDataFlow dataflow;
float master_vol;
UINT32 channel_count;
float *channel_vols;
CRITICAL_SECTION lock;
struct list entry;
} AudioSession;
typedef struct _AudioSessionWrapper {
IAudioSessionControl2 IAudioSessionControl2_iface;
IChannelAudioVolume IChannelAudioVolume_iface;
ISimpleAudioVolume ISimpleAudioVolume_iface;
LONG ref;
@ -95,9 +103,9 @@ struct ACImpl {
IAudioClient IAudioClient_iface;
IAudioRenderClient IAudioRenderClient_iface;
IAudioCaptureClient IAudioCaptureClient_iface;
ISimpleAudioVolume ISimpleAudioVolume_iface;
IAudioClock IAudioClock_iface;
IAudioClock2 IAudioClock2_iface;
IAudioStreamVolume IAudioStreamVolume_iface;
LONG ref;
@ -109,6 +117,7 @@ struct ACImpl {
DWORD flags;
AUDCLNT_SHAREMODE share;
HANDLE event;
float *vols;
AudioDeviceID adevid;
AudioQueueRef aqueue;
@ -147,6 +156,8 @@ static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
static const IAudioClockVtbl AudioClock_Vtbl;
static const IAudioClock2Vtbl AudioClock2_Vtbl;
static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
static HANDLE g_timer_q;
@ -156,6 +167,7 @@ static struct list g_sessions = LIST_INIT(g_sessions);
static HRESULT AudioClock_GetPosition_nolock(ACImpl *This, UINT64 *pos,
UINT64 *qpctime, BOOL raw);
static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
static HRESULT ca_setvol(ACImpl *This, UINT32 index);
static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
{
@ -177,9 +189,14 @@ static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSession
return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
}
static inline ACImpl *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
{
return CONTAINING_RECORD(iface, ACImpl, ISimpleAudioVolume_iface);
return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
}
static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
{
return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
}
static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
@ -192,6 +209,11 @@ static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
}
static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
{
return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
}
BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
{
if(reason == DLL_PROCESS_ATTACH){
@ -397,9 +419,9 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(AudioDeviceID *adevid, IMMDevice *dev,
This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
This->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
This->dataflow = dataflow;
@ -469,10 +491,13 @@ static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
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);
HeapFree(GetProcessHeap(), 0, This->public_buffer);
CoTaskMemFree(This->fmt);
IMMDevice_Release(This->parent);
@ -684,7 +709,8 @@ static HRESULT ca_setup_aqueue(AudioDeviceID did, EDataFlow flow,
return S_OK;
}
static AudioSession *create_session(const GUID *guid, EDataFlow flow)
static AudioSession *create_session(const GUID *guid, EDataFlow flow,
int num_channels)
{
AudioSession *ret;
@ -700,6 +726,21 @@ static AudioSession *create_session(const GUID *guid, EDataFlow flow)
list_add_head(&g_sessions, &ret->entry);
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;
ret->master_vol = 1.f;
return ret;
}
@ -711,6 +752,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
ACImpl *This = impl_from_IAudioClient(iface);
HRESULT hr;
OSStatus sc;
int i;
TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
@ -803,38 +845,70 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
}
}
This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
if(!This->vols){
AudioQueueDispose(This->aqueue, 1);
This->aqueue = NULL;
CoTaskMemFree(This->fmt);
This->fmt = NULL;
OSSpinLockUnlock(&This->lock);
return E_OUTOFMEMORY;
}
for(i = 0; i < fmt->nChannels; ++i)
This->vols[i] = 1.f;
This->share = mode;
This->flags = flags;
EnterCriticalSection(&g_sessions_lock);
if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
This->session = create_session(&GUID_NULL, This->dataflow);
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)
LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
if(IsEqualGUID(sessionguid, &session->guid) &&
This->dataflow == session->dataflow)
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);
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;
}
@ -845,6 +919,8 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
LeaveCriticalSection(&g_sessions_lock);
ca_setvol(This, -1);
OSSpinLockUnlock(&This->lock);
return S_OK;
@ -1374,6 +1450,10 @@ static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
}
*ppv = &This->IAudioCaptureClient_iface;
}else if(IsEqualIID(riid, &IID_IAudioClock)){
*ppv = &This->IAudioClock_iface;
}else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
*ppv = &This->IAudioStreamVolume_iface;
}else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
if(!This->session_wrapper){
This->session_wrapper = AudioSessionWrapper_Create(This);
@ -1384,10 +1464,26 @@ static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
}
*ppv = &This->session_wrapper->IAudioSessionControl2_iface;
}else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
if(!This->session_wrapper){
This->session_wrapper = AudioSessionWrapper_Create(This);
if(!This->session_wrapper){
OSSpinLockUnlock(&This->lock);
return E_OUTOFMEMORY;
}
}
*ppv = &This->session_wrapper->IChannelAudioVolume_iface;
}else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
*ppv = &This->ISimpleAudioVolume_iface;
}else if(IsEqualIID(riid, &IID_IAudioClock)){
*ppv = &This->IAudioClock_iface;
if(!This->session_wrapper){
This->session_wrapper = AudioSessionWrapper_Create(This);
if(!This->session_wrapper){
OSSpinLockUnlock(&This->lock);
return E_OUTOFMEMORY;
}
}
*ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
}
if(*ppv){
@ -1920,6 +2016,8 @@ static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
return NULL;
ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
ret->client = client;
ret->session = client->session;
@ -2170,6 +2268,57 @@ static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
AudioSessionControl_SetDuckingPreference
};
/* index == -1 means set all channels, otherwise sets only the given channel */
static HRESULT ca_setvol(ACImpl *This, UINT32 index)
{
AudioObjectPropertyAddress addr;
float level;
OSStatus sc;
if(index == (UINT32)-1){
HRESULT ret = S_OK;
UINT32 i;
for(i = 0; i < This->fmt->nChannels; ++i){
HRESULT hr;
hr = ca_setvol(This, i);
if(FAILED(hr))
ret = hr;
}
return ret;
}
level = This->session->master_vol * This->session->channel_vols[index] *
This->vols[index];
addr.mScope = This->scope;
addr.mSelector = kAudioDevicePropertyVolumeScalar;
addr.mElement = index + 1;
sc = AudioObjectSetPropertyData(This->adevid, &addr, 0, NULL,
sizeof(float), &level);
if(sc != noErr){
WARN("Setting _VolumeScalar property failed: %lx\n", sc);
return E_FAIL;
}
return S_OK;
}
static HRESULT ca_session_setvol(AudioSession *session, UINT32 index)
{
HRESULT ret = S_OK;
ACImpl *client;
LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
HRESULT hr;
hr = ca_setvol(client, index);
if(FAILED(hr))
ret = hr;
}
return ret;
}
static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
ISimpleAudioVolume *iface, REFIID riid, void **ppv)
{
@ -2193,42 +2342,65 @@ static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
{
ACImpl *This = impl_from_ISimpleAudioVolume(iface);
return IAudioClient_AddRef(&This->IAudioClient_iface);
AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
}
static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
{
ACImpl *This = impl_from_ISimpleAudioVolume(iface);
return IAudioClient_Release(&This->IAudioClient_iface);
AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
}
static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
ISimpleAudioVolume *iface, float level, const GUID *context)
{
ACImpl *This = impl_from_ISimpleAudioVolume(iface);
AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
AudioSession *session = This->session;
HRESULT ret;
FIXME("(%p)->(%f, %p) - stub\n", This, level, context);
TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
return E_NOTIMPL;
if(level < 0.f || level > 1.f)
return E_INVALIDARG;
if(context)
FIXME("Notifications not supported yet\n");
EnterCriticalSection(&session->lock);
session->master_vol = level;
ret = ca_session_setvol(session, -1);
LeaveCriticalSection(&session->lock);
return ret;
}
static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
ISimpleAudioVolume *iface, float *level)
{
ACImpl *This = impl_from_ISimpleAudioVolume(iface);
AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
AudioSession *session = This->session;
FIXME("(%p)->(%p) - stub\n", This, level);
TRACE("(%p)->(%p)\n", session, level);
return E_NOTIMPL;
if(!level)
return NULL_PTR_ERR;
*level = session->master_vol;
return S_OK;
}
static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
BOOL mute, const GUID *context)
{
ACImpl *This = impl_from_ISimpleAudioVolume(iface);
AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
AudioSession *session = This->session;
FIXME("(%p)->(%u, %p) - stub\n", This, mute, context);
FIXME("(%p)->(%u, %p) - stub\n", session, mute, context);
return E_NOTIMPL;
}
@ -2236,9 +2408,13 @@ static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
BOOL *mute)
{
ACImpl *This = impl_from_ISimpleAudioVolume(iface);
AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
AudioSession *session = This->session;
FIXME("(%p)->(%p) - stub\n", This, mute);
FIXME("(%p)->(%p) - stub\n", session, mute);
if(!mute)
return NULL_PTR_ERR;
return E_NOTIMPL;
}
@ -2253,3 +2429,322 @@ static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
SimpleAudioVolume_SetMute,
SimpleAudioVolume_GetMute
};
static HRESULT WINAPI AudioStreamVolume_QueryInterface(
IAudioStreamVolume *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_IAudioStreamVolume))
*ppv = iface;
if(*ppv){
IUnknown_AddRef((IUnknown*)*ppv);
return S_OK;
}
WARN("Unknown interface %s\n", debugstr_guid(riid));
return E_NOINTERFACE;
}
static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
{
ACImpl *This = impl_from_IAudioStreamVolume(iface);
return IAudioClient_AddRef(&This->IAudioClient_iface);
}
static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
{
ACImpl *This = impl_from_IAudioStreamVolume(iface);
return IAudioClient_Release(&This->IAudioClient_iface);
}
static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
IAudioStreamVolume *iface, UINT32 *out)
{
ACImpl *This = impl_from_IAudioStreamVolume(iface);
TRACE("(%p)->(%p)\n", This, out);
if(!out)
return E_POINTER;
*out = This->fmt->nChannels;
return S_OK;
}
static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
IAudioStreamVolume *iface, UINT32 index, float level)
{
ACImpl *This = impl_from_IAudioStreamVolume(iface);
HRESULT ret;
TRACE("(%p)->(%d, %f)\n", This, index, level);
if(level < 0.f || level > 1.f)
return E_INVALIDARG;
if(index >= This->fmt->nChannels)
return E_INVALIDARG;
OSSpinLockLock(&This->lock);
This->vols[index] = level;
ret = ca_setvol(This, index);
OSSpinLockUnlock(&This->lock);
return ret;
}
static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
IAudioStreamVolume *iface, UINT32 index, float *level)
{
ACImpl *This = impl_from_IAudioStreamVolume(iface);
TRACE("(%p)->(%d, %p)\n", This, index, level);
if(!level)
return E_POINTER;
if(index >= This->fmt->nChannels)
return E_INVALIDARG;
*level = This->vols[index];
return S_OK;
}
static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
IAudioStreamVolume *iface, UINT32 count, const float *levels)
{
ACImpl *This = impl_from_IAudioStreamVolume(iface);
int i;
HRESULT ret;
TRACE("(%p)->(%d, %p)\n", This, count, levels);
if(!levels)
return E_POINTER;
if(count != This->fmt->nChannels)
return E_INVALIDARG;
OSSpinLockLock(&This->lock);
for(i = 0; i < count; ++i)
This->vols[i] = levels[i];
ret = ca_setvol(This, -1);
OSSpinLockUnlock(&This->lock);
return ret;
}
static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
IAudioStreamVolume *iface, UINT32 count, float *levels)
{
ACImpl *This = impl_from_IAudioStreamVolume(iface);
int i;
TRACE("(%p)->(%d, %p)\n", This, count, levels);
if(!levels)
return E_POINTER;
if(count != This->fmt->nChannels)
return E_INVALIDARG;
OSSpinLockLock(&This->lock);
for(i = 0; i < count; ++i)
levels[i] = This->vols[i];
OSSpinLockUnlock(&This->lock);
return S_OK;
}
static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
{
AudioStreamVolume_QueryInterface,
AudioStreamVolume_AddRef,
AudioStreamVolume_Release,
AudioStreamVolume_GetChannelCount,
AudioStreamVolume_SetChannelVolume,
AudioStreamVolume_GetChannelVolume,
AudioStreamVolume_SetAllVolumes,
AudioStreamVolume_GetAllVolumes
};
static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
IChannelAudioVolume *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_IChannelAudioVolume))
*ppv = iface;
if(*ppv){
IUnknown_AddRef((IUnknown*)*ppv);
return S_OK;
}
WARN("Unknown interface %s\n", debugstr_guid(riid));
return E_NOINTERFACE;
}
static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
{
AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
}
static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
{
AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
}
static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
IChannelAudioVolume *iface, UINT32 *out)
{
AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
AudioSession *session = This->session;
TRACE("(%p)->(%p)\n", session, out);
if(!out)
return NULL_PTR_ERR;
*out = session->channel_count;
return S_OK;
}
static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
IChannelAudioVolume *iface, UINT32 index, float level,
const GUID *context)
{
AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
AudioSession *session = This->session;
HRESULT ret;
TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
wine_dbgstr_guid(context));
if(level < 0.f || level > 1.f)
return E_INVALIDARG;
if(index >= session->channel_count)
return E_INVALIDARG;
if(context)
FIXME("Notifications not supported yet\n");
EnterCriticalSection(&session->lock);
session->channel_vols[index] = level;
ret = ca_session_setvol(session, index);
LeaveCriticalSection(&session->lock);
return ret;
}
static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
IChannelAudioVolume *iface, UINT32 index, float *level)
{
AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
AudioSession *session = This->session;
TRACE("(%p)->(%d, %p)\n", session, index, level);
if(!level)
return NULL_PTR_ERR;
if(index >= session->channel_count)
return E_INVALIDARG;
*level = session->channel_vols[index];
return S_OK;
}
static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
IChannelAudioVolume *iface, UINT32 count, const float *levels,
const GUID *context)
{
AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
AudioSession *session = This->session;
int i;
HRESULT ret;
TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
wine_dbgstr_guid(context));
if(!levels)
return NULL_PTR_ERR;
if(count != session->channel_count)
return E_INVALIDARG;
if(context)
FIXME("Notifications not supported yet\n");
EnterCriticalSection(&session->lock);
for(i = 0; i < count; ++i)
session->channel_vols[i] = levels[i];
ret = ca_session_setvol(session, -1);
LeaveCriticalSection(&session->lock);
return ret;
}
static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
IChannelAudioVolume *iface, UINT32 count, float *levels)
{
AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
AudioSession *session = This->session;
int i;
TRACE("(%p)->(%d, %p)\n", session, count, levels);
if(!levels)
return NULL_PTR_ERR;
if(count != session->channel_count)
return E_INVALIDARG;
for(i = 0; i < count; ++i)
levels[i] = session->channel_vols[i];
return S_OK;
}
static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
{
ChannelAudioVolume_QueryInterface,
ChannelAudioVolume_AddRef,
ChannelAudioVolume_Release,
ChannelAudioVolume_GetChannelCount,
ChannelAudioVolume_SetChannelVolume,
ChannelAudioVolume_GetChannelVolume,
ChannelAudioVolume_SetAllVolumes,
ChannelAudioVolume_GetAllVolumes
};