Wine-devel
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
February 2022
- 87 participants
- 926 discussions
On Windows, loading gdi32.dll causes user32.dll to be loaded. It's
important for win32u, which is not fully functional until user32 sets
KernelCallbackTable.
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/gdi32/Makefile.in | 2 +-
dlls/gdi32/objects.c | 25 ++++---------------------
2 files changed, 5 insertions(+), 22 deletions(-)
2
1
This reverts 50aeb5e777d9a8836f5530755afab10e042c623f. Previously
problematic code is now moved to win32u and doesn't use setupapi.
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/user32/Makefile.in | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
2
1
17 Feb '22
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/winealsa.drv/mmdevdrv.c | 23 ++++++++++-------------
1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c
index 10f2951a0e6..48694710719 100644
--- a/dlls/winealsa.drv/mmdevdrv.c
+++ b/dlls/winealsa.drv/mmdevdrv.c
@@ -109,8 +109,6 @@ struct ACImpl {
UINT32 channel_count;
struct alsa_stream *stream;
- BOOL initted;
-
HANDLE timer;
CRITICAL_SECTION lock;
@@ -578,7 +576,7 @@ static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
IUnknown_Release(This->pUnkFTMarshal);
This->lock.DebugInfo->Spare[0] = 0;
DeleteCriticalSection(&This->lock);
- if(This->initted){
+ if(This->session){
EnterCriticalSection(&g_sessions_lock);
list_remove(&This->entry);
LeaveCriticalSection(&g_sessions_lock);
@@ -969,7 +967,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
EnterCriticalSection(&g_sessions_lock);
EnterCriticalSection(&This->lock);
- if(This->initted){
+ if(This->stream){
LeaveCriticalSection(&This->lock);
LeaveCriticalSection(&g_sessions_lock);
return AUDCLNT_E_ALREADY_INITIALIZED;
@@ -1201,7 +1199,6 @@ exit:
This->vols = NULL;
}else{
This->stream = stream;
- This->initted = TRUE;
}
LeaveCriticalSection(&This->lock);
@@ -1223,7 +1220,7 @@ static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface,
EnterCriticalSection(&This->lock);
- if(!This->initted){
+ if(!This->stream){
LeaveCriticalSection(&This->lock);
return AUDCLNT_E_NOT_INITIALIZED;
}
@@ -1248,7 +1245,7 @@ static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
EnterCriticalSection(&This->lock);
- if(!This->initted){
+ if(!This->stream){
LeaveCriticalSection(&This->lock);
return AUDCLNT_E_NOT_INITIALIZED;
}
@@ -1282,7 +1279,7 @@ static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
EnterCriticalSection(&This->lock);
- if(!This->initted){
+ if(!This->stream){
LeaveCriticalSection(&This->lock);
return AUDCLNT_E_NOT_INITIALIZED;
}
@@ -1873,7 +1870,7 @@ static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
EnterCriticalSection(&This->lock);
- if(!This->initted){
+ if(!This->stream){
LeaveCriticalSection(&This->lock);
return AUDCLNT_E_NOT_INITIALIZED;
}
@@ -1942,7 +1939,7 @@ static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
EnterCriticalSection(&This->lock);
- if(!This->initted){
+ if(!This->stream){
LeaveCriticalSection(&This->lock);
return AUDCLNT_E_NOT_INITIALIZED;
}
@@ -1971,7 +1968,7 @@ static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface)
EnterCriticalSection(&This->lock);
- if(!This->initted){
+ if(!This->stream){
LeaveCriticalSection(&This->lock);
return AUDCLNT_E_NOT_INITIALIZED;
}
@@ -2023,7 +2020,7 @@ static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
EnterCriticalSection(&This->lock);
- if(!This->initted){
+ if(!This->stream){
LeaveCriticalSection(&This->lock);
return AUDCLNT_E_NOT_INITIALIZED;
}
@@ -2059,7 +2056,7 @@ static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
EnterCriticalSection(&This->lock);
- if(!This->initted){
+ if(!This->stream){
LeaveCriticalSection(&This->lock);
return AUDCLNT_E_NOT_INITIALIZED;
}
--
2.25.1
2
1
[PATCH 7/8] winealsa: Move the stream creation to AudioClient_Initialize().
by Huw Davies 17 Feb '22
by Huw Davies 17 Feb '22
17 Feb '22
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/winealsa.drv/mmdevdrv.c | 56 ++++++++++++++++++++----------------
1 file changed, 31 insertions(+), 25 deletions(-)
diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c
index 8a80acd871a..10f2951a0e6 100644
--- a/dlls/winealsa.drv/mmdevdrv.c
+++ b/dlls/winealsa.drv/mmdevdrv.c
@@ -507,19 +507,6 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient
This->dataflow = dataflow;
memcpy(This->alsa_name, alsa_name, len + 1);
- This->stream = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This->stream));
- if(!This->stream){
- HeapFree(GetProcessHeap(), 0, This);
- return E_OUTOFMEMORY;
- }
-
- hr = alsa_open_device(alsa_name, dataflow, &This->stream->pcm_handle, &This->stream->hw_params);
- if(FAILED(hr)){
- HeapFree(GetProcessHeap(), 0, This->stream);
- HeapFree(GetProcessHeap(), 0, This);
- return hr;
- }
-
InitializeCriticalSection(&This->lock);
This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ACImpl.lock");
@@ -591,21 +578,23 @@ static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
IUnknown_Release(This->pUnkFTMarshal);
This->lock.DebugInfo->Spare[0] = 0;
DeleteCriticalSection(&This->lock);
- snd_pcm_drop(stream->pcm_handle);
- snd_pcm_close(stream->pcm_handle);
if(This->initted){
EnterCriticalSection(&g_sessions_lock);
list_remove(&This->entry);
LeaveCriticalSection(&g_sessions_lock);
}
HeapFree(GetProcessHeap(), 0, This->vols);
- HeapFree(GetProcessHeap(), 0, stream->local_buffer);
- HeapFree(GetProcessHeap(), 0, stream->remapping_buf);
- HeapFree(GetProcessHeap(), 0, stream->silence_buf);
- HeapFree(GetProcessHeap(), 0, stream->tmp_buffer);
- HeapFree(GetProcessHeap(), 0, stream->hw_params);
- CoTaskMemFree(stream->fmt);
- HeapFree(GetProcessHeap(), 0, stream);
+ if (stream){
+ snd_pcm_drop(stream->pcm_handle);
+ snd_pcm_close(stream->pcm_handle);
+ HeapFree(GetProcessHeap(), 0, stream->local_buffer);
+ HeapFree(GetProcessHeap(), 0, stream->remapping_buf);
+ HeapFree(GetProcessHeap(), 0, stream->silence_buf);
+ HeapFree(GetProcessHeap(), 0, stream->tmp_buffer);
+ HeapFree(GetProcessHeap(), 0, stream->hw_params);
+ CoTaskMemFree(stream->fmt);
+ HeapFree(GetProcessHeap(), 0, stream);
+ }
HeapFree(GetProcessHeap(), 0, This);
}
return ref;
@@ -919,7 +908,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
const GUID *sessionguid)
{
ACImpl *This = impl_from_IAudioClient3(iface);
- struct alsa_stream *stream = This->stream;
+ struct alsa_stream *stream;
snd_pcm_sw_params_t *sw_params = NULL;
snd_pcm_format_t format;
unsigned int rate, alsa_period_us;
@@ -988,6 +977,20 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
dump_fmt(fmt);
+ stream = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This->stream));
+ if(!stream){
+ LeaveCriticalSection(&This->lock);
+ LeaveCriticalSection(&g_sessions_lock);
+ return E_OUTOFMEMORY;
+ }
+
+ hr = alsa_open_device(This->alsa_name, This->dataflow, &stream->pcm_handle, &stream->hw_params);
+ if(FAILED(hr)){
+ LeaveCriticalSection(&This->lock);
+ LeaveCriticalSection(&g_sessions_lock);
+ return hr;
+ }
+
stream->need_remapping = map_channels(This, fmt, &stream->alsa_channels, stream->alsa_channel_map) == S_OK;
if((err = snd_pcm_hw_params_any(stream->pcm_handle, stream->hw_params)) < 0){
@@ -1180,8 +1183,6 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
list_add_tail(&This->session->clients, &This->entry);
- This->initted = TRUE;
-
TRACE("ALSA period: %lu frames\n", stream->alsa_period_frames);
TRACE("ALSA buffer: %lu frames\n", stream->alsa_bufsize_frames);
TRACE("MMDevice period: %u frames\n", stream->mmdev_period_frames);
@@ -1190,12 +1191,17 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
exit:
HeapFree(GetProcessHeap(), 0, sw_params);
if(FAILED(hr)){
+ snd_pcm_close(stream->pcm_handle);
HeapFree(GetProcessHeap(), 0, stream->local_buffer);
stream->local_buffer = NULL;
CoTaskMemFree(stream->fmt);
stream->fmt = NULL;
+ HeapFree(GetProcessHeap(), 0, stream);
HeapFree(GetProcessHeap(), 0, This->vols);
This->vols = NULL;
+ }else{
+ This->stream = stream;
+ This->initted = TRUE;
}
LeaveCriticalSection(&This->lock);
--
2.25.1
2
1
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/winealsa.drv/alsa.c | 291 +++++++++++++++++++++++++++++++++++
dlls/winealsa.drv/mmdevdrv.c | 150 ++----------------
dlls/winealsa.drv/unixlib.h | 11 ++
3 files changed, 317 insertions(+), 135 deletions(-)
diff --git a/dlls/winealsa.drv/alsa.c b/dlls/winealsa.drv/alsa.c
index 320d676effb..0680383f59b 100644
--- a/dlls/winealsa.drv/alsa.c
+++ b/dlls/winealsa.drv/alsa.c
@@ -453,6 +453,27 @@ static NTSTATUS get_endpoint_ids(void *args)
return STATUS_SUCCESS;
}
+static WAVEFORMATEXTENSIBLE *clone_format(const WAVEFORMATEX *fmt)
+{
+ WAVEFORMATEXTENSIBLE *ret;
+ size_t size;
+
+ if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
+ size = sizeof(WAVEFORMATEXTENSIBLE);
+ else
+ size = sizeof(WAVEFORMATEX);
+
+ ret = malloc(size);
+ if(!ret)
+ return NULL;
+
+ memcpy(ret, fmt, size);
+
+ ret->Format.cbSize = size - sizeof(WAVEFORMATEX);
+
+ return ret;
+}
+
static HRESULT alsa_open_device(const char *alsa_name, EDataFlow flow, snd_pcm_t **pcm_handle,
snd_pcm_hw_params_t **hw_params)
{
@@ -486,6 +507,78 @@ static HRESULT alsa_open_device(const char *alsa_name, EDataFlow flow, snd_pcm_t
return S_OK;
}
+static snd_pcm_format_t alsa_format(const WAVEFORMATEX *fmt)
+{
+ snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN;
+ const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
+
+ if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
+ (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
+ IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
+ if(fmt->wBitsPerSample == 8)
+ format = SND_PCM_FORMAT_U8;
+ else if(fmt->wBitsPerSample == 16)
+ format = SND_PCM_FORMAT_S16_LE;
+ else if(fmt->wBitsPerSample == 24)
+ format = SND_PCM_FORMAT_S24_3LE;
+ else if(fmt->wBitsPerSample == 32)
+ format = SND_PCM_FORMAT_S32_LE;
+ else
+ WARN("Unsupported bit depth: %u\n", fmt->wBitsPerSample);
+ if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
+ fmt->wBitsPerSample != fmtex->Samples.wValidBitsPerSample){
+ if(fmtex->Samples.wValidBitsPerSample == 20 && fmt->wBitsPerSample == 24)
+ format = SND_PCM_FORMAT_S20_3LE;
+ else
+ WARN("Unsupported ValidBits: %u\n", fmtex->Samples.wValidBitsPerSample);
+ }
+ }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
+ (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
+ IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
+ if(fmt->wBitsPerSample == 32)
+ format = SND_PCM_FORMAT_FLOAT_LE;
+ else if(fmt->wBitsPerSample == 64)
+ format = SND_PCM_FORMAT_FLOAT64_LE;
+ else
+ WARN("Unsupported float size: %u\n", fmt->wBitsPerSample);
+ }else
+ WARN("Unknown wave format: %04x\n", fmt->wFormatTag);
+ return format;
+}
+
+static int alsa_channel_index(DWORD flag)
+{
+ switch(flag){
+ case SPEAKER_FRONT_LEFT:
+ return 0;
+ case SPEAKER_FRONT_RIGHT:
+ return 1;
+ case SPEAKER_BACK_LEFT:
+ return 2;
+ case SPEAKER_BACK_RIGHT:
+ return 3;
+ case SPEAKER_FRONT_CENTER:
+ return 4;
+ case SPEAKER_LOW_FREQUENCY:
+ return 5;
+ case SPEAKER_SIDE_LEFT:
+ return 6;
+ case SPEAKER_SIDE_RIGHT:
+ return 7;
+ }
+ return -1;
+}
+
+static BOOL need_remapping(const WAVEFORMATEX *fmt, int *map)
+{
+ unsigned int i;
+ for(i = 0; i < fmt->nChannels; ++i){
+ if(map[i] != i)
+ return TRUE;
+ }
+ return FALSE;
+}
+
static DWORD get_channel_mask(unsigned int channels)
{
switch(channels){
@@ -512,6 +605,203 @@ static DWORD get_channel_mask(unsigned int channels)
return 0;
}
+static HRESULT map_channels(EDataFlow flow, const WAVEFORMATEX *fmt, int *alsa_channels, int *map)
+{
+ BOOL need_remap;
+
+ if(flow != eCapture && (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE || fmt->nChannels > 2) ){
+ WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
+ DWORD mask, flag = SPEAKER_FRONT_LEFT;
+ UINT i = 0;
+
+ if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
+ fmtex->dwChannelMask != 0)
+ mask = fmtex->dwChannelMask;
+ else
+ mask = get_channel_mask(fmt->nChannels);
+
+ *alsa_channels = 0;
+
+ while(i < fmt->nChannels && !(flag & SPEAKER_RESERVED)){
+ if(mask & flag){
+ map[i] = alsa_channel_index(flag);
+ TRACE("Mapping mmdevapi channel %u (0x%x) to ALSA channel %d\n",
+ i, flag, map[i]);
+ if(map[i] >= *alsa_channels)
+ *alsa_channels = map[i] + 1;
+ ++i;
+ }
+ flag <<= 1;
+ }
+
+ while(i < fmt->nChannels){
+ map[i] = *alsa_channels;
+ TRACE("Mapping mmdevapi channel %u to ALSA channel %d\n",
+ i, map[i]);
+ ++*alsa_channels;
+ ++i;
+ }
+
+ for(i = 0; i < fmt->nChannels; ++i){
+ if(map[i] == -1){
+ map[i] = *alsa_channels;
+ ++*alsa_channels;
+ TRACE("Remapping mmdevapi channel %u to ALSA channel %d\n",
+ i, map[i]);
+ }
+ }
+
+ need_remap = need_remapping(fmt, map);
+ }else{
+ *alsa_channels = fmt->nChannels;
+
+ need_remap = FALSE;
+ }
+
+ TRACE("need_remapping: %u, alsa_channels: %d\n", need_remap, *alsa_channels);
+
+ return need_remap ? S_OK : S_FALSE;
+}
+
+static NTSTATUS is_format_supported(void *args)
+{
+ struct is_format_supported_params *params = args;
+ const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)params->fmt_in;
+ snd_pcm_t *pcm_handle;
+ snd_pcm_hw_params_t *hw_params;
+ snd_pcm_format_mask_t *formats = NULL;
+ snd_pcm_format_t format;
+ WAVEFORMATEXTENSIBLE *closest = NULL;
+ unsigned int max = 0, min = 0;
+ int err;
+ int alsa_channels, alsa_channel_map[32];
+
+ params->result = S_OK;
+
+ if(!params->fmt_in || (params->share == AUDCLNT_SHAREMODE_SHARED && !params->fmt_out))
+ params->result = E_POINTER;
+ else if(params->share != AUDCLNT_SHAREMODE_SHARED && params->share != AUDCLNT_SHAREMODE_EXCLUSIVE)
+ params->result = E_INVALIDARG;
+ else if(params->fmt_in->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
+ if(params->fmt_in->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
+ params->result = E_INVALIDARG;
+ else if(params->fmt_in->nAvgBytesPerSec == 0 || params->fmt_in->nBlockAlign == 0 ||
+ (fmtex->Samples.wValidBitsPerSample > params->fmt_in->wBitsPerSample))
+ params->result = E_INVALIDARG;
+ }
+ if(FAILED(params->result))
+ return STATUS_SUCCESS;
+
+ if(params->fmt_in->nChannels == 0){
+ params->result = AUDCLNT_E_UNSUPPORTED_FORMAT;
+ return STATUS_SUCCESS;
+ }
+
+ params->result = alsa_open_device(params->alsa_name, params->flow, &pcm_handle, &hw_params);
+ if(FAILED(params->result))
+ return STATUS_SUCCESS;
+
+ if((err = snd_pcm_hw_params_any(pcm_handle, hw_params)) < 0){
+ params->result = AUDCLNT_E_DEVICE_INVALIDATED;
+ goto exit;
+ }
+
+ formats = calloc(1, snd_pcm_format_mask_sizeof());
+ if(!formats){
+ params->result = E_OUTOFMEMORY;
+ goto exit;
+ }
+
+ snd_pcm_hw_params_get_format_mask(hw_params, formats);
+ format = alsa_format(params->fmt_in);
+ if (format == SND_PCM_FORMAT_UNKNOWN ||
+ !snd_pcm_format_mask_test(formats, format)){
+ params->result = AUDCLNT_E_UNSUPPORTED_FORMAT;
+ goto exit;
+ }
+
+ closest = clone_format(params->fmt_in);
+ if(!closest){
+ params->result = E_OUTOFMEMORY;
+ goto exit;
+ }
+
+ if((err = snd_pcm_hw_params_get_rate_min(hw_params, &min, NULL)) < 0){
+ params->result = AUDCLNT_E_DEVICE_INVALIDATED;
+ WARN("Unable to get min rate: %d (%s)\n", err, snd_strerror(err));
+ goto exit;
+ }
+
+ if((err = snd_pcm_hw_params_get_rate_max(hw_params, &max, NULL)) < 0){
+ params->result = AUDCLNT_E_DEVICE_INVALIDATED;
+ WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err));
+ goto exit;
+ }
+
+ if(params->fmt_in->nSamplesPerSec < min || params->fmt_in->nSamplesPerSec > max){
+ params->result = AUDCLNT_E_UNSUPPORTED_FORMAT;
+ goto exit;
+ }
+
+ if((err = snd_pcm_hw_params_get_channels_min(hw_params, &min)) < 0){
+ params->result = AUDCLNT_E_DEVICE_INVALIDATED;
+ WARN("Unable to get min channels: %d (%s)\n", err, snd_strerror(err));
+ goto exit;
+ }
+
+ if((err = snd_pcm_hw_params_get_channels_max(hw_params, &max)) < 0){
+ params->result = AUDCLNT_E_DEVICE_INVALIDATED;
+ WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err));
+ goto exit;
+ }
+ if(params->fmt_in->nChannels > max){
+ params->result = S_FALSE;
+ closest->Format.nChannels = max;
+ }else if(params->fmt_in->nChannels < min){
+ params->result = S_FALSE;
+ closest->Format.nChannels = min;
+ }
+
+ map_channels(params->flow, params->fmt_in, &alsa_channels, alsa_channel_map);
+
+ if(alsa_channels > max){
+ params->result = S_FALSE;
+ closest->Format.nChannels = max;
+ }
+
+ if(closest->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
+ closest->dwChannelMask = get_channel_mask(closest->Format.nChannels);
+
+ if(params->fmt_in->nBlockAlign != params->fmt_in->nChannels * params->fmt_in->wBitsPerSample / 8 ||
+ params->fmt_in->nAvgBytesPerSec != params->fmt_in->nBlockAlign * params->fmt_in->nSamplesPerSec ||
+ (params->fmt_in->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
+ fmtex->Samples.wValidBitsPerSample < params->fmt_in->wBitsPerSample))
+ params->result = S_FALSE;
+
+ if(params->share == AUDCLNT_SHAREMODE_EXCLUSIVE && params->fmt_in->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
+ if(fmtex->dwChannelMask == 0 || fmtex->dwChannelMask & SPEAKER_RESERVED)
+ params->result = S_FALSE;
+ }
+
+exit:
+ if(params->result == S_FALSE && !params->fmt_out)
+ params->result = AUDCLNT_E_UNSUPPORTED_FORMAT;
+
+ if(params->result == S_FALSE && params->fmt_out) {
+ closest->Format.nBlockAlign = closest->Format.nChannels * closest->Format.wBitsPerSample / 8;
+ closest->Format.nAvgBytesPerSec = closest->Format.nBlockAlign * closest->Format.nSamplesPerSec;
+ if(closest->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
+ closest->Samples.wValidBitsPerSample = closest->Format.wBitsPerSample;
+ memcpy(params->fmt_out, closest, closest->Format.cbSize);
+ }
+ free(closest);
+ free(formats);
+ free(hw_params);
+ snd_pcm_close(pcm_handle);
+
+ return STATUS_SUCCESS;
+}
+
static NTSTATUS get_mix_format(void *args)
{
struct get_mix_format_params *params = args;
@@ -632,5 +922,6 @@ exit:
unixlib_entry_t __wine_unix_call_funcs[] =
{
get_endpoint_ids,
+ is_format_supported,
get_mix_format,
};
diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c
index 24c6755d697..8a80acd871a 100644
--- a/dlls/winealsa.drv/mmdevdrv.c
+++ b/dlls/winealsa.drv/mmdevdrv.c
@@ -1296,150 +1296,30 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
WAVEFORMATEX **out)
{
ACImpl *This = impl_from_IAudioClient3(iface);
- snd_pcm_format_mask_t *formats = NULL;
- snd_pcm_format_t format;
- HRESULT hr = S_OK;
- WAVEFORMATEX *closest = NULL;
- unsigned int max = 0, min = 0;
- int err;
- int alsa_channels, alsa_channel_map[32];
+ struct is_format_supported_params params;
TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out);
+ if(fmt) dump_fmt(fmt);
- if(!fmt || (mode == AUDCLNT_SHAREMODE_SHARED && !out))
- return E_POINTER;
-
- if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
- return E_INVALIDARG;
-
- if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
- fmt->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
- return E_INVALIDARG;
-
- dump_fmt(fmt);
+ params.alsa_name = This->alsa_name;
+ params.flow = This->dataflow;
+ params.share = mode;
+ params.fmt_in = fmt;
+ params.fmt_out = NULL;
if(out){
*out = NULL;
- if(mode != AUDCLNT_SHAREMODE_SHARED)
- out = NULL;
+ if(mode == AUDCLNT_SHAREMODE_SHARED)
+ params.fmt_out = CoTaskMemAlloc(sizeof(*params.fmt_out));
}
+ ALSA_CALL(is_format_supported, ¶ms);
- if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
- (fmt->nAvgBytesPerSec == 0 ||
- fmt->nBlockAlign == 0 ||
- ((WAVEFORMATEXTENSIBLE*)fmt)->Samples.wValidBitsPerSample > fmt->wBitsPerSample))
- return E_INVALIDARG;
-
- if(fmt->nChannels == 0)
- return AUDCLNT_E_UNSUPPORTED_FORMAT;
-
- EnterCriticalSection(&This->lock);
-
- if((err = snd_pcm_hw_params_any(This->stream->pcm_handle, This->stream->hw_params)) < 0){
- hr = AUDCLNT_E_DEVICE_INVALIDATED;
- goto exit;
- }
-
- formats = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
- snd_pcm_format_mask_sizeof());
- if(!formats){
- hr = E_OUTOFMEMORY;
- goto exit;
- }
-
- snd_pcm_hw_params_get_format_mask(This->stream->hw_params, formats);
- format = alsa_format(fmt);
- if (format == SND_PCM_FORMAT_UNKNOWN ||
- !snd_pcm_format_mask_test(formats, format)){
- hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
- goto exit;
- }
-
- closest = clone_format(fmt);
- if(!closest){
- hr = E_OUTOFMEMORY;
- goto exit;
- }
-
- if((err = snd_pcm_hw_params_get_rate_min(This->stream->hw_params, &min, NULL)) < 0){
- hr = AUDCLNT_E_DEVICE_INVALIDATED;
- WARN("Unable to get min rate: %d (%s)\n", err, snd_strerror(err));
- goto exit;
- }
-
- if((err = snd_pcm_hw_params_get_rate_max(This->stream->hw_params, &max, NULL)) < 0){
- hr = AUDCLNT_E_DEVICE_INVALIDATED;
- WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err));
- goto exit;
- }
-
- if(fmt->nSamplesPerSec < min || fmt->nSamplesPerSec > max){
- hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
- goto exit;
- }
-
- if((err = snd_pcm_hw_params_get_channels_min(This->stream->hw_params, &min)) < 0){
- hr = AUDCLNT_E_DEVICE_INVALIDATED;
- WARN("Unable to get min channels: %d (%s)\n", err, snd_strerror(err));
- goto exit;
- }
-
- if((err = snd_pcm_hw_params_get_channels_max(This->stream->hw_params, &max)) < 0){
- hr = AUDCLNT_E_DEVICE_INVALIDATED;
- WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err));
- goto exit;
- }
- if(fmt->nChannels > max){
- hr = S_FALSE;
- closest->nChannels = max;
- }else if(fmt->nChannels < min){
- hr = S_FALSE;
- closest->nChannels = min;
- }
-
- map_channels(This, fmt, &alsa_channels, alsa_channel_map);
-
- if(alsa_channels > max){
- hr = S_FALSE;
- closest->nChannels = max;
- }
-
- if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
- ((WAVEFORMATEXTENSIBLE*)closest)->dwChannelMask = get_channel_mask(closest->nChannels);
-
- if(fmt->nBlockAlign != fmt->nChannels * fmt->wBitsPerSample / 8 ||
- fmt->nAvgBytesPerSec != fmt->nBlockAlign * fmt->nSamplesPerSec ||
- (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
- ((WAVEFORMATEXTENSIBLE*)fmt)->Samples.wValidBitsPerSample < fmt->wBitsPerSample))
- hr = S_FALSE;
-
- if(mode == AUDCLNT_SHAREMODE_EXCLUSIVE &&
- fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
- if(((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask == 0 ||
- ((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask & SPEAKER_RESERVED)
- hr = S_FALSE;
- }
-
-exit:
- LeaveCriticalSection(&This->lock);
- HeapFree(GetProcessHeap(), 0, formats);
-
- if(hr == S_FALSE && !out)
- hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
-
- if(hr == S_FALSE && out) {
- closest->nBlockAlign =
- closest->nChannels * closest->wBitsPerSample / 8;
- closest->nAvgBytesPerSec =
- closest->nBlockAlign * closest->nSamplesPerSec;
- if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
- ((WAVEFORMATEXTENSIBLE*)closest)->Samples.wValidBitsPerSample = closest->wBitsPerSample;
- *out = closest;
- } else
- CoTaskMemFree(closest);
+ if(params.result == S_FALSE)
+ *out = ¶ms.fmt_out->Format;
+ else
+ CoTaskMemFree(params.fmt_out);
- TRACE("returning: %08x\n", hr);
- return hr;
+ return params.result;
}
static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
diff --git a/dlls/winealsa.drv/unixlib.h b/dlls/winealsa.drv/unixlib.h
index ef5b470e1ed..cd8d303b5d3 100644
--- a/dlls/winealsa.drv/unixlib.h
+++ b/dlls/winealsa.drv/unixlib.h
@@ -67,6 +67,16 @@ struct get_endpoint_ids_params
unsigned int default_idx;
};
+struct is_format_supported_params
+{
+ const char *alsa_name;
+ EDataFlow flow;
+ AUDCLNT_SHAREMODE share;
+ const WAVEFORMATEX *fmt_in;
+ WAVEFORMATEXTENSIBLE *fmt_out;
+ HRESULT result;
+};
+
struct get_mix_format_params
{
const char *alsa_name;
@@ -78,6 +88,7 @@ struct get_mix_format_params
enum alsa_funcs
{
alsa_get_endpoint_ids,
+ alsa_is_format_supported,
alsa_get_mix_format,
};
--
2.25.1
2
1
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/winealsa.drv/alsa.c | 178 +++++++++++++++++++++++++++++++++++
dlls/winealsa.drv/mmdevdrv.c | 126 +++----------------------
dlls/winealsa.drv/unixlib.h | 9 ++
3 files changed, 199 insertions(+), 114 deletions(-)
diff --git a/dlls/winealsa.drv/alsa.c b/dlls/winealsa.drv/alsa.c
index ae05c7a8b9b..320d676effb 100644
--- a/dlls/winealsa.drv/alsa.c
+++ b/dlls/winealsa.drv/alsa.c
@@ -39,6 +39,7 @@
#include "wine/list.h"
#include "wine/unixlib.h"
+#include "initguid.h"
#include "unixlib.h"
WINE_DEFAULT_DEBUG_CHANNEL(alsa);
@@ -452,7 +453,184 @@ static NTSTATUS get_endpoint_ids(void *args)
return STATUS_SUCCESS;
}
+static HRESULT alsa_open_device(const char *alsa_name, EDataFlow flow, snd_pcm_t **pcm_handle,
+ snd_pcm_hw_params_t **hw_params)
+{
+ snd_pcm_stream_t pcm_stream;
+ int err;
+
+ if(flow == eRender)
+ pcm_stream = SND_PCM_STREAM_PLAYBACK;
+ else if(flow == eCapture)
+ pcm_stream = SND_PCM_STREAM_CAPTURE;
+ else
+ return E_UNEXPECTED;
+
+ err = snd_pcm_open(pcm_handle, alsa_name, pcm_stream, SND_PCM_NONBLOCK);
+ if(err < 0){
+ WARN("Unable to open PCM \"%s\": %d (%s)\n", alsa_name, err, snd_strerror(err));
+ switch(err){
+ case -EBUSY:
+ return AUDCLNT_E_DEVICE_IN_USE;
+ default:
+ return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
+ }
+ }
+
+ *hw_params = malloc(snd_pcm_hw_params_sizeof());
+ if(!*hw_params){
+ snd_pcm_close(*pcm_handle);
+ return E_OUTOFMEMORY;
+ }
+
+ return S_OK;
+}
+
+static DWORD get_channel_mask(unsigned int channels)
+{
+ switch(channels){
+ case 0:
+ return 0;
+ case 1:
+ return KSAUDIO_SPEAKER_MONO;
+ case 2:
+ return KSAUDIO_SPEAKER_STEREO;
+ case 3:
+ return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
+ case 4:
+ return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
+ case 5:
+ return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
+ case 6:
+ return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
+ case 7:
+ return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
+ case 8:
+ return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
+ }
+ FIXME("Unknown speaker configuration: %u\n", channels);
+ return 0;
+}
+
+static NTSTATUS get_mix_format(void *args)
+{
+ struct get_mix_format_params *params = args;
+ WAVEFORMATEXTENSIBLE *fmt = params->fmt;
+ snd_pcm_t *pcm_handle;
+ snd_pcm_hw_params_t *hw_params;
+ snd_pcm_format_mask_t *formats;
+ unsigned int max_rate, max_channels;
+ int err;
+
+ params->result = alsa_open_device(params->alsa_name, params->flow, &pcm_handle, &hw_params);
+ if(FAILED(params->result))
+ return STATUS_SUCCESS;
+
+ formats = calloc(1, snd_pcm_format_mask_sizeof());
+ if(!formats){
+ free(hw_params);
+ snd_pcm_close(pcm_handle);
+ params->result = E_OUTOFMEMORY;
+ return STATUS_SUCCESS;
+ }
+
+ if((err = snd_pcm_hw_params_any(pcm_handle, hw_params)) < 0){
+ WARN("Unable to get hw_params: %d (%s)\n", err, snd_strerror(err));
+ params->result = AUDCLNT_E_DEVICE_INVALIDATED;
+ goto exit;
+ }
+
+ snd_pcm_hw_params_get_format_mask(hw_params, formats);
+
+ fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+ if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_FLOAT_LE)){
+ fmt->Format.wBitsPerSample = 32;
+ fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
+ }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S16_LE)){
+ fmt->Format.wBitsPerSample = 16;
+ fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+ }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_U8)){
+ fmt->Format.wBitsPerSample = 8;
+ fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+ }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S32_LE)){
+ fmt->Format.wBitsPerSample = 32;
+ fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+ }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S24_3LE)){
+ fmt->Format.wBitsPerSample = 24;
+ fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+ }else{
+ ERR("Didn't recognize any available ALSA formats\n");
+ params->result = AUDCLNT_E_DEVICE_INVALIDATED;
+ goto exit;
+ }
+
+ if((err = snd_pcm_hw_params_get_channels_max(hw_params, &max_channels)) < 0){
+ WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err));
+ params->result = AUDCLNT_E_DEVICE_INVALIDATED;
+ goto exit;
+ }
+
+ if(max_channels > 6)
+ fmt->Format.nChannels = 2;
+ else
+ fmt->Format.nChannels = max_channels;
+
+ if(fmt->Format.nChannels > 1 && (fmt->Format.nChannels & 0x1)){
+ /* For most hardware on Windows, users must choose a configuration with an even
+ * number of channels (stereo, quad, 5.1, 7.1). Users can then disable
+ * channels, but those channels are still reported to applications from
+ * GetMixFormat! Some applications behave badly if given an odd number of
+ * channels (e.g. 2.1). */
+
+ if(fmt->Format.nChannels < max_channels)
+ fmt->Format.nChannels += 1;
+ else
+ /* We could "fake" more channels and downmix the emulated channels,
+ * but at that point you really ought to tweak your ALSA setup or
+ * just use PulseAudio. */
+ WARN("Some Windows applications behave badly with an odd number of channels (%u)!\n", fmt->Format.nChannels);
+ }
+
+ fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
+
+ if((err = snd_pcm_hw_params_get_rate_max(hw_params, &max_rate, NULL)) < 0){
+ WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err));
+ params->result = AUDCLNT_E_DEVICE_INVALIDATED;
+ goto exit;
+ }
+
+ if(max_rate >= 48000)
+ fmt->Format.nSamplesPerSec = 48000;
+ else if(max_rate >= 44100)
+ fmt->Format.nSamplesPerSec = 44100;
+ else if(max_rate >= 22050)
+ fmt->Format.nSamplesPerSec = 22050;
+ else if(max_rate >= 11025)
+ fmt->Format.nSamplesPerSec = 11025;
+ else if(max_rate >= 8000)
+ fmt->Format.nSamplesPerSec = 8000;
+ else{
+ ERR("Unknown max rate: %u\n", max_rate);
+ params->result = AUDCLNT_E_DEVICE_INVALIDATED;
+ goto exit;
+ }
+
+ fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample * fmt->Format.nChannels) / 8;
+ fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec * fmt->Format.nBlockAlign;
+
+ fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
+ fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
+
+exit:
+ free(formats);
+ free(hw_params);
+ snd_pcm_close(pcm_handle);
+
+ return STATUS_SUCCESS;
+}
+
unixlib_entry_t __wine_unix_call_funcs[] =
{
get_endpoint_ids,
+ get_mix_format,
};
diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c
index ecd74d373aa..24c6755d697 100644
--- a/dlls/winealsa.drv/mmdevdrv.c
+++ b/dlls/winealsa.drv/mmdevdrv.c
@@ -1446,11 +1446,7 @@ static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
WAVEFORMATEX **pwfx)
{
ACImpl *This = impl_from_IAudioClient3(iface);
- WAVEFORMATEXTENSIBLE *fmt;
- snd_pcm_format_mask_t *formats;
- unsigned int max_rate, max_channels;
- int err;
- HRESULT hr = S_OK;
+ struct get_mix_format_params params;
TRACE("(%p)->(%p)\n", This, pwfx);
@@ -1458,119 +1454,21 @@ static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
return E_POINTER;
*pwfx = NULL;
- fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
- if(!fmt)
+ params.alsa_name = This->alsa_name;
+ params.flow = This->dataflow;
+ params.fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
+ if(!params.fmt)
return E_OUTOFMEMORY;
- formats = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_format_mask_sizeof());
- if(!formats){
- CoTaskMemFree(fmt);
- return E_OUTOFMEMORY;
- }
-
- EnterCriticalSection(&This->lock);
-
- if((err = snd_pcm_hw_params_any(This->stream->pcm_handle, This->stream->hw_params)) < 0){
- WARN("Unable to get hw_params: %d (%s)\n", err, snd_strerror(err));
- hr = AUDCLNT_E_DEVICE_INVALIDATED;
- goto exit;
- }
-
- snd_pcm_hw_params_get_format_mask(This->stream->hw_params, formats);
-
- fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
- if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_FLOAT_LE)){
- fmt->Format.wBitsPerSample = 32;
- fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
- }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S16_LE)){
- fmt->Format.wBitsPerSample = 16;
- fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
- }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_U8)){
- fmt->Format.wBitsPerSample = 8;
- fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
- }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S32_LE)){
- fmt->Format.wBitsPerSample = 32;
- fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
- }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S24_3LE)){
- fmt->Format.wBitsPerSample = 24;
- fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
- }else{
- ERR("Didn't recognize any available ALSA formats\n");
- hr = AUDCLNT_E_DEVICE_INVALIDATED;
- goto exit;
- }
-
- if((err = snd_pcm_hw_params_get_channels_max(This->stream->hw_params,
- &max_channels)) < 0){
- WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err));
- hr = AUDCLNT_E_DEVICE_INVALIDATED;
- goto exit;
- }
-
- if(max_channels > 6)
- fmt->Format.nChannels = 2;
- else
- fmt->Format.nChannels = max_channels;
-
- if(fmt->Format.nChannels > 1 && (fmt->Format.nChannels & 0x1)){
- /* For most hardware on Windows, users must choose a configuration with an even
- * number of channels (stereo, quad, 5.1, 7.1). Users can then disable
- * channels, but those channels are still reported to applications from
- * GetMixFormat! Some applications behave badly if given an odd number of
- * channels (e.g. 2.1). */
-
- if(fmt->Format.nChannels < max_channels)
- fmt->Format.nChannels += 1;
- else
- /* We could "fake" more channels and downmix the emulated channels,
- * but at that point you really ought to tweak your ALSA setup or
- * just use PulseAudio. */
- WARN("Some Windows applications behave badly with an odd number of channels (%u)!\n", fmt->Format.nChannels);
- }
-
- fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
+ ALSA_CALL(get_mix_format, ¶ms);
- if((err = snd_pcm_hw_params_get_rate_max(This->stream->hw_params, &max_rate,
- NULL)) < 0){
- WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err));
- hr = AUDCLNT_E_DEVICE_INVALIDATED;
- goto exit;
- }
-
- if(max_rate >= 48000)
- fmt->Format.nSamplesPerSec = 48000;
- else if(max_rate >= 44100)
- fmt->Format.nSamplesPerSec = 44100;
- else if(max_rate >= 22050)
- fmt->Format.nSamplesPerSec = 22050;
- else if(max_rate >= 11025)
- fmt->Format.nSamplesPerSec = 11025;
- else if(max_rate >= 8000)
- fmt->Format.nSamplesPerSec = 8000;
- else{
- ERR("Unknown max rate: %u\n", max_rate);
- hr = AUDCLNT_E_DEVICE_INVALIDATED;
- goto exit;
- }
-
- fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
- fmt->Format.nChannels) / 8;
- fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
- fmt->Format.nBlockAlign;
-
- fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
- fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
-
- dump_fmt((WAVEFORMATEX*)fmt);
- *pwfx = (WAVEFORMATEX*)fmt;
-
-exit:
- LeaveCriticalSection(&This->lock);
- if(FAILED(hr))
- CoTaskMemFree(fmt);
- HeapFree(GetProcessHeap(), 0, formats);
+ if(SUCCEEDED(params.result)){
+ *pwfx = ¶ms.fmt->Format;
+ dump_fmt(*pwfx);
+ } else
+ CoTaskMemFree(params.fmt);
- return hr;
+ return params.result;
}
static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface,
diff --git a/dlls/winealsa.drv/unixlib.h b/dlls/winealsa.drv/unixlib.h
index 8a20710b7e5..ef5b470e1ed 100644
--- a/dlls/winealsa.drv/unixlib.h
+++ b/dlls/winealsa.drv/unixlib.h
@@ -67,9 +67,18 @@ struct get_endpoint_ids_params
unsigned int default_idx;
};
+struct get_mix_format_params
+{
+ const char *alsa_name;
+ EDataFlow flow;
+ WAVEFORMATEXTENSIBLE *fmt;
+ HRESULT result;
+};
+
enum alsa_funcs
{
alsa_get_endpoint_ids,
+ alsa_get_mix_format,
};
extern unixlib_handle_t alsa_handle;
--
2.25.1
2
1
This will allow GetMixFormat and IsFormatSupported to share
this code without needing a stream.
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/winealsa.drv/mmdevdrv.c | 50 ++++++++++++++++++++++--------------
1 file changed, 31 insertions(+), 19 deletions(-)
diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c
index f1bc2fd0247..ecd74d373aa 100644
--- a/dlls/winealsa.drv/mmdevdrv.c
+++ b/dlls/winealsa.drv/mmdevdrv.c
@@ -442,10 +442,37 @@ static BOOL get_alsa_name_by_guid(GUID *guid, char *name, DWORD name_size, EData
return FALSE;
}
+static HRESULT alsa_open_device(const char *alsa_name, EDataFlow flow, snd_pcm_t **pcm_handle,
+ snd_pcm_hw_params_t **hw_params)
+{
+ int err;
+
+ if(flow != eRender && flow != eCapture)
+ return E_UNEXPECTED;
+
+ err = snd_pcm_open(pcm_handle, alsa_name, alsa_get_direction(flow), SND_PCM_NONBLOCK);
+ if(err < 0){
+ WARN("Unable to open PCM \"%s\": %d (%s)\n", alsa_name, err, snd_strerror(err));
+ switch(err){
+ case -EBUSY:
+ return AUDCLNT_E_DEVICE_IN_USE;
+ default:
+ return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
+ }
+ }
+
+ *hw_params = HeapAlloc(GetProcessHeap(), 0, snd_pcm_hw_params_sizeof());
+ if(!*hw_params){
+ snd_pcm_close(*pcm_handle);
+ return E_OUTOFMEMORY;
+ }
+
+ return S_OK;
+}
+
HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out)
{
ACImpl *This;
- int err;
char alsa_name[256];
EDataFlow dataflow;
HRESULT hr;
@@ -486,26 +513,11 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient
return E_OUTOFMEMORY;
}
- err = snd_pcm_open(&This->stream->pcm_handle, alsa_name, alsa_get_direction(dataflow), SND_PCM_NONBLOCK);
- if(err < 0){
- HeapFree(GetProcessHeap(), 0, This->stream);
- HeapFree(GetProcessHeap(), 0, This);
- WARN("Unable to open PCM \"%s\": %d (%s)\n", alsa_name, err, snd_strerror(err));
- switch(err){
- case -EBUSY:
- return AUDCLNT_E_DEVICE_IN_USE;
- default:
- return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
- }
- }
-
- This->stream->hw_params = HeapAlloc(GetProcessHeap(), 0,
- snd_pcm_hw_params_sizeof());
- if(!This->stream->hw_params){
- snd_pcm_close(This->stream->pcm_handle);
+ hr = alsa_open_device(alsa_name, dataflow, &This->stream->pcm_handle, &This->stream->hw_params);
+ if(FAILED(hr)){
HeapFree(GetProcessHeap(), 0, This->stream);
HeapFree(GetProcessHeap(), 0, This);
- return E_OUTOFMEMORY;
+ return hr;
}
InitializeCriticalSection(&This->lock);
--
2.25.1
2
1
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/winealsa.drv/mmdevdrv.c | 691 ++++++++++++++++++-----------------
dlls/winealsa.drv/unixlib.h | 35 ++
2 files changed, 385 insertions(+), 341 deletions(-)
diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c
index 0549752dc3f..f1bc2fd0247 100644
--- a/dlls/winealsa.drv/mmdevdrv.c
+++ b/dlls/winealsa.drv/mmdevdrv.c
@@ -101,42 +101,17 @@ struct ACImpl {
LONG ref;
- snd_pcm_t *pcm_handle;
- snd_pcm_uframes_t alsa_bufsize_frames, alsa_period_frames, safe_rewind_frames;
- snd_pcm_hw_params_t *hw_params; /* does not hold state between calls */
- snd_pcm_format_t alsa_format;
-
- LARGE_INTEGER last_period_time;
-
IMMDevice *parent;
IUnknown *pUnkFTMarshal;
EDataFlow dataflow;
- WAVEFORMATEX *fmt;
- DWORD flags;
- AUDCLNT_SHAREMODE share;
- HANDLE event;
float *vols;
UINT32 channel_count;
+ struct alsa_stream *stream;
- BOOL need_remapping;
- int alsa_channels;
- int alsa_channel_map[32];
-
- BOOL initted, started;
- REFERENCE_TIME mmdev_period_rt;
- UINT64 written_frames, last_pos_frames;
- UINT32 bufsize_frames, held_frames, tmp_buffer_frames, mmdev_period_frames;
- snd_pcm_uframes_t remapping_buf_frames;
- UINT32 lcl_offs_frames; /* offs into local_buffer where valid data starts */
- UINT32 wri_offs_frames; /* where to write fresh data in local_buffer */
- UINT32 hidden_frames; /* ALSA reserve to ensure continuous rendering */
- UINT32 vol_adjusted_frames; /* Frames we've already adjusted the volume of but didn't write yet */
- UINT32 data_in_alsa_frames;
+ BOOL initted;
HANDLE timer;
- BYTE *local_buffer, *tmp_buffer, *remapping_buf, *silence_buf;
- LONG32 getbuf_last; /* <0 when using tmp_buffer */
CRITICAL_SECTION lock;
@@ -505,8 +480,15 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient
This->dataflow = dataflow;
memcpy(This->alsa_name, alsa_name, len + 1);
- err = snd_pcm_open(&This->pcm_handle, alsa_name, alsa_get_direction(dataflow), SND_PCM_NONBLOCK);
+ This->stream = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This->stream));
+ if(!This->stream){
+ HeapFree(GetProcessHeap(), 0, This);
+ return E_OUTOFMEMORY;
+ }
+
+ err = snd_pcm_open(&This->stream->pcm_handle, alsa_name, alsa_get_direction(dataflow), SND_PCM_NONBLOCK);
if(err < 0){
+ HeapFree(GetProcessHeap(), 0, This->stream);
HeapFree(GetProcessHeap(), 0, This);
WARN("Unable to open PCM \"%s\": %d (%s)\n", alsa_name, err, snd_strerror(err));
switch(err){
@@ -517,10 +499,11 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient
}
}
- This->hw_params = HeapAlloc(GetProcessHeap(), 0,
+ This->stream->hw_params = HeapAlloc(GetProcessHeap(), 0,
snd_pcm_hw_params_sizeof());
- if(!This->hw_params){
- snd_pcm_close(This->pcm_handle);
+ if(!This->stream->hw_params){
+ snd_pcm_close(This->stream->pcm_handle);
+ HeapFree(GetProcessHeap(), 0, This->stream);
HeapFree(GetProcessHeap(), 0, This);
return E_OUTOFMEMORY;
}
@@ -574,6 +557,7 @@ static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface)
static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
{
ACImpl *This = impl_from_IAudioClient3(iface);
+ struct alsa_stream *stream = This->stream;
ULONG ref;
ref = InterlockedDecrement(&This->ref);
@@ -595,20 +579,21 @@ static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
IUnknown_Release(This->pUnkFTMarshal);
This->lock.DebugInfo->Spare[0] = 0;
DeleteCriticalSection(&This->lock);
- snd_pcm_drop(This->pcm_handle);
- snd_pcm_close(This->pcm_handle);
+ snd_pcm_drop(stream->pcm_handle);
+ snd_pcm_close(stream->pcm_handle);
if(This->initted){
EnterCriticalSection(&g_sessions_lock);
list_remove(&This->entry);
LeaveCriticalSection(&g_sessions_lock);
}
HeapFree(GetProcessHeap(), 0, This->vols);
- HeapFree(GetProcessHeap(), 0, This->local_buffer);
- HeapFree(GetProcessHeap(), 0, This->remapping_buf);
- HeapFree(GetProcessHeap(), 0, This->silence_buf);
- HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
- HeapFree(GetProcessHeap(), 0, This->hw_params);
- CoTaskMemFree(This->fmt);
+ HeapFree(GetProcessHeap(), 0, stream->local_buffer);
+ HeapFree(GetProcessHeap(), 0, stream->remapping_buf);
+ HeapFree(GetProcessHeap(), 0, stream->silence_buf);
+ HeapFree(GetProcessHeap(), 0, stream->tmp_buffer);
+ HeapFree(GetProcessHeap(), 0, stream->hw_params);
+ CoTaskMemFree(stream->fmt);
+ HeapFree(GetProcessHeap(), 0, stream);
HeapFree(GetProcessHeap(), 0, This);
}
return ref;
@@ -904,16 +889,16 @@ static HRESULT map_channels(ACImpl *This, const WAVEFORMATEX *fmt, int *alsa_cha
return need_remap ? S_OK : S_FALSE;
}
-static void silence_buffer(ACImpl *This, BYTE *buffer, UINT32 frames)
+static void silence_buffer(struct alsa_stream *stream, BYTE *buffer, UINT32 frames)
{
- WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
- if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
- (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
+ WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)stream->fmt;
+ if((stream->fmt->wFormatTag == WAVE_FORMAT_PCM ||
+ (stream->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
- This->fmt->wBitsPerSample == 8)
- memset(buffer, 128, frames * This->fmt->nBlockAlign);
+ stream->fmt->wBitsPerSample == 8)
+ memset(buffer, 128, frames * stream->fmt->nBlockAlign);
else
- memset(buffer, 0, frames * This->fmt->nBlockAlign);
+ memset(buffer, 0, frames * stream->fmt->nBlockAlign);
}
static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
@@ -922,6 +907,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
const GUID *sessionguid)
{
ACImpl *This = impl_from_IAudioClient3(iface);
+ struct alsa_stream *stream = This->stream;
snd_pcm_sw_params_t *sw_params = NULL;
snd_pcm_format_t format;
unsigned int rate, alsa_period_us;
@@ -990,15 +976,15 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
dump_fmt(fmt);
- This->need_remapping = map_channels(This, fmt, &This->alsa_channels, This->alsa_channel_map) == S_OK;
+ stream->need_remapping = map_channels(This, fmt, &stream->alsa_channels, stream->alsa_channel_map) == S_OK;
- if((err = snd_pcm_hw_params_any(This->pcm_handle, This->hw_params)) < 0){
+ if((err = snd_pcm_hw_params_any(stream->pcm_handle, stream->hw_params)) < 0){
WARN("Unable to get hw_params: %d (%s)\n", err, snd_strerror(err));
hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
goto exit;
}
- if((err = snd_pcm_hw_params_set_access(This->pcm_handle, This->hw_params,
+ if((err = snd_pcm_hw_params_set_access(stream->pcm_handle, stream->hw_params,
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0){
WARN("Unable to set access: %d (%s)\n", err, snd_strerror(err));
hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
@@ -1011,7 +997,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
goto exit;
}
- if((err = snd_pcm_hw_params_set_format(This->pcm_handle, This->hw_params,
+ if((err = snd_pcm_hw_params_set_format(stream->pcm_handle, stream->hw_params,
format)) < 0){
WARN("Unable to set ALSA format to %u: %d (%s)\n", format, err,
snd_strerror(err));
@@ -1019,10 +1005,10 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
goto exit;
}
- This->alsa_format = format;
+ stream->alsa_format = format;
rate = fmt->nSamplesPerSec;
- if((err = snd_pcm_hw_params_set_rate_near(This->pcm_handle, This->hw_params,
+ if((err = snd_pcm_hw_params_set_rate_near(stream->pcm_handle, stream->hw_params,
&rate, NULL)) < 0){
WARN("Unable to set rate to %u: %d (%s)\n", rate, err,
snd_strerror(err));
@@ -1030,52 +1016,52 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
goto exit;
}
- if((err = snd_pcm_hw_params_set_channels(This->pcm_handle, This->hw_params,
- This->alsa_channels)) < 0){
+ if((err = snd_pcm_hw_params_set_channels(stream->pcm_handle, stream->hw_params,
+ stream->alsa_channels)) < 0){
WARN("Unable to set channels to %u: %d (%s)\n", fmt->nChannels, err,
snd_strerror(err));
hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
goto exit;
}
- This->mmdev_period_rt = period;
- alsa_period_us = This->mmdev_period_rt / 10;
- if((err = snd_pcm_hw_params_set_period_time_near(This->pcm_handle,
- This->hw_params, &alsa_period_us, NULL)) < 0)
+ stream->mmdev_period_rt = period;
+ alsa_period_us = stream->mmdev_period_rt / 10;
+ if((err = snd_pcm_hw_params_set_period_time_near(stream->pcm_handle,
+ stream->hw_params, &alsa_period_us, NULL)) < 0)
WARN("Unable to set period time near %u: %d (%s)\n", alsa_period_us,
err, snd_strerror(err));
/* ALSA updates the output variable alsa_period_us */
- This->mmdev_period_frames = MulDiv(fmt->nSamplesPerSec,
- This->mmdev_period_rt, 10000000);
+ stream->mmdev_period_frames = MulDiv(fmt->nSamplesPerSec,
+ stream->mmdev_period_rt, 10000000);
/* Buffer 4 ALSA periods if large enough, else 4 mmdevapi periods */
- This->alsa_bufsize_frames = This->mmdev_period_frames * 4;
+ stream->alsa_bufsize_frames = stream->mmdev_period_frames * 4;
if(err < 0 || alsa_period_us < period / 10)
- err = snd_pcm_hw_params_set_buffer_size_near(This->pcm_handle,
- This->hw_params, &This->alsa_bufsize_frames);
+ err = snd_pcm_hw_params_set_buffer_size_near(stream->pcm_handle,
+ stream->hw_params, &stream->alsa_bufsize_frames);
else{
unsigned int periods = 4;
- err = snd_pcm_hw_params_set_periods_near(This->pcm_handle, This->hw_params, &periods, NULL);
+ err = snd_pcm_hw_params_set_periods_near(stream->pcm_handle, stream->hw_params, &periods, NULL);
}
if(err < 0)
WARN("Unable to set buffer size: %d (%s)\n", err, snd_strerror(err));
- if((err = snd_pcm_hw_params(This->pcm_handle, This->hw_params)) < 0){
+ if((err = snd_pcm_hw_params(stream->pcm_handle, stream->hw_params)) < 0){
WARN("Unable to set hw params: %d (%s)\n", err, snd_strerror(err));
hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
goto exit;
}
- if((err = snd_pcm_hw_params_get_period_size(This->hw_params,
- &This->alsa_period_frames, NULL)) < 0){
+ if((err = snd_pcm_hw_params_get_period_size(stream->hw_params,
+ &stream->alsa_period_frames, NULL)) < 0){
WARN("Unable to get period size: %d (%s)\n", err, snd_strerror(err));
hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
goto exit;
}
- if((err = snd_pcm_hw_params_get_buffer_size(This->hw_params,
- &This->alsa_bufsize_frames)) < 0){
+ if((err = snd_pcm_hw_params_get_buffer_size(stream->hw_params,
+ &stream->alsa_bufsize_frames)) < 0){
WARN("Unable to get buffer size: %d (%s)\n", err, snd_strerror(err));
hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
goto exit;
@@ -1087,34 +1073,34 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
goto exit;
}
- if((err = snd_pcm_sw_params_current(This->pcm_handle, sw_params)) < 0){
+ if((err = snd_pcm_sw_params_current(stream->pcm_handle, sw_params)) < 0){
WARN("Unable to get sw_params: %d (%s)\n", err, snd_strerror(err));
hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
goto exit;
}
- if((err = snd_pcm_sw_params_set_start_threshold(This->pcm_handle,
+ if((err = snd_pcm_sw_params_set_start_threshold(stream->pcm_handle,
sw_params, 1)) < 0){
WARN("Unable set start threshold to 1: %d (%s)\n", err, snd_strerror(err));
hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
goto exit;
}
- if((err = snd_pcm_sw_params_set_stop_threshold(This->pcm_handle,
- sw_params, This->alsa_bufsize_frames)) < 0){
+ if((err = snd_pcm_sw_params_set_stop_threshold(stream->pcm_handle,
+ sw_params, stream->alsa_bufsize_frames)) < 0){
WARN("Unable set stop threshold to %lu: %d (%s)\n",
- This->alsa_bufsize_frames, err, snd_strerror(err));
+ stream->alsa_bufsize_frames, err, snd_strerror(err));
hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
goto exit;
}
- if((err = snd_pcm_sw_params(This->pcm_handle, sw_params)) < 0){
+ if((err = snd_pcm_sw_params(stream->pcm_handle, sw_params)) < 0){
WARN("Unable to set sw params: %d (%s)\n", err, snd_strerror(err));
hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
goto exit;
}
- if((err = snd_pcm_prepare(This->pcm_handle)) < 0){
+ if((err = snd_pcm_prepare(stream->pcm_handle)) < 0){
WARN("Unable to prepare device: %d (%s)\n", err, snd_strerror(err));
hr = AUDCLNT_E_ENDPOINT_CREATE_FAILED;
goto exit;
@@ -1125,42 +1111,42 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
* or surprising rounding as seen with 22050x8x1 with Pulse:
* ALSA period 220 vs. 221 frames in mmdevapi and
* buffer 883 vs. 2205 frames in mmdevapi! */
- This->bufsize_frames = MulDiv(duration, fmt->nSamplesPerSec, 10000000);
+ stream->bufsize_frames = MulDiv(duration, fmt->nSamplesPerSec, 10000000);
if(mode == AUDCLNT_SHAREMODE_EXCLUSIVE)
- This->bufsize_frames -= This->bufsize_frames % This->mmdev_period_frames;
- This->hidden_frames = This->alsa_period_frames + This->mmdev_period_frames +
+ stream->bufsize_frames -= stream->bufsize_frames % stream->mmdev_period_frames;
+ stream->hidden_frames = stream->alsa_period_frames + stream->mmdev_period_frames +
MulDiv(fmt->nSamplesPerSec, EXTRA_SAFE_RT, 10000000);
/* leave no less than about 1.33ms or 256 bytes of data after a rewind */
- This->safe_rewind_frames = max(256 / fmt->nBlockAlign, MulDiv(133, fmt->nSamplesPerSec, 100000));
+ stream->safe_rewind_frames = max(256 / fmt->nBlockAlign, MulDiv(133, fmt->nSamplesPerSec, 100000));
/* Check if the ALSA buffer is so small that it will run out before
* the next MMDevAPI period tick occurs. Allow a little wiggle room
* with 120% of the period time. */
- if(This->alsa_bufsize_frames < 1.2 * This->mmdev_period_frames)
+ if(stream->alsa_bufsize_frames < 1.2 * stream->mmdev_period_frames)
FIXME("ALSA buffer time is too small. Expect underruns. (%lu < %u * 1.2)\n",
- This->alsa_bufsize_frames, This->mmdev_period_frames);
+ stream->alsa_bufsize_frames, stream->mmdev_period_frames);
- This->fmt = clone_format(fmt);
- if(!This->fmt){
+ stream->fmt = clone_format(fmt);
+ if(!stream->fmt){
hr = E_OUTOFMEMORY;
goto exit;
}
- This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
- This->bufsize_frames * fmt->nBlockAlign);
- if(!This->local_buffer){
+ stream->local_buffer = HeapAlloc(GetProcessHeap(), 0,
+ stream->bufsize_frames * fmt->nBlockAlign);
+ if(!stream->local_buffer){
hr = E_OUTOFMEMORY;
goto exit;
}
- silence_buffer(This, This->local_buffer, This->bufsize_frames);
+ silence_buffer(stream, stream->local_buffer, stream->bufsize_frames);
- This->silence_buf = HeapAlloc(GetProcessHeap(), 0,
- This->alsa_period_frames * This->fmt->nBlockAlign);
- if(!This->silence_buf){
+ stream->silence_buf = HeapAlloc(GetProcessHeap(), 0,
+ stream->alsa_period_frames * stream->fmt->nBlockAlign);
+ if(!stream->silence_buf){
hr = E_OUTOFMEMORY;
goto exit;
}
- silence_buffer(This, This->silence_buf, This->alsa_period_frames);
+ silence_buffer(stream, stream->silence_buf, stream->alsa_period_frames);
This->channel_count = fmt->nChannels;
This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float));
@@ -1172,8 +1158,8 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
for(i = 0; i < This->channel_count; ++i)
This->vols[i] = 1.f;
- This->share = mode;
- This->flags = flags;
+ stream->share = mode;
+ stream->flags = flags;
hr = get_audio_session(sessionguid, This->parent, This->channel_count,
&This->session);
@@ -1184,18 +1170,18 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
This->initted = TRUE;
- TRACE("ALSA period: %lu frames\n", This->alsa_period_frames);
- TRACE("ALSA buffer: %lu frames\n", This->alsa_bufsize_frames);
- TRACE("MMDevice period: %u frames\n", This->mmdev_period_frames);
- TRACE("MMDevice buffer: %u frames\n", This->bufsize_frames);
+ TRACE("ALSA period: %lu frames\n", stream->alsa_period_frames);
+ TRACE("ALSA buffer: %lu frames\n", stream->alsa_bufsize_frames);
+ TRACE("MMDevice period: %u frames\n", stream->mmdev_period_frames);
+ TRACE("MMDevice buffer: %u frames\n", stream->bufsize_frames);
exit:
HeapFree(GetProcessHeap(), 0, sw_params);
if(FAILED(hr)){
- HeapFree(GetProcessHeap(), 0, This->local_buffer);
- This->local_buffer = NULL;
- CoTaskMemFree(This->fmt);
- This->fmt = NULL;
+ HeapFree(GetProcessHeap(), 0, stream->local_buffer);
+ stream->local_buffer = NULL;
+ CoTaskMemFree(stream->fmt);
+ stream->fmt = NULL;
HeapFree(GetProcessHeap(), 0, This->vols);
This->vols = NULL;
}
@@ -1210,6 +1196,7 @@ static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface,
UINT32 *out)
{
ACImpl *This = impl_from_IAudioClient3(iface);
+ struct alsa_stream *stream = This->stream;
TRACE("(%p)->(%p)\n", This, out);
@@ -1223,7 +1210,7 @@ static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface,
return AUDCLNT_E_NOT_INITIALIZED;
}
- *out = This->bufsize_frames;
+ *out = stream->bufsize_frames;
LeaveCriticalSection(&This->lock);
@@ -1234,6 +1221,7 @@ static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
REFERENCE_TIME *latency)
{
ACImpl *This = impl_from_IAudioClient3(iface);
+ struct alsa_stream *stream = This->stream;
TRACE("(%p)->(%p)\n", This, latency);
@@ -1253,10 +1241,10 @@ static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
* + EXTRA_SAFE (~4ms) to allow for late callback invocation / fluctuation;
* + alsa_period such that ALSA always has at least one period to play. */
if(This->dataflow == eRender)
- *latency = MulDiv(This->hidden_frames, 10000000, This->fmt->nSamplesPerSec);
+ *latency = MulDiv(stream->hidden_frames, 10000000, stream->fmt->nSamplesPerSec);
else
- *latency = MulDiv(This->alsa_period_frames, 10000000, This->fmt->nSamplesPerSec)
- + This->mmdev_period_rt;
+ *latency = MulDiv(stream->alsa_period_frames, 10000000, stream->fmt->nSamplesPerSec)
+ + stream->mmdev_period_rt;
LeaveCriticalSection(&This->lock);
@@ -1267,6 +1255,7 @@ static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
UINT32 *out)
{
ACImpl *This = impl_from_IAudioClient3(iface);
+ struct alsa_stream *stream = This->stream;
TRACE("(%p)->(%p)\n", This, out);
@@ -1281,7 +1270,7 @@ static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
}
/* padding is solely updated at callback time in shared mode */
- *out = This->held_frames;
+ *out = stream->held_frames;
LeaveCriticalSection(&This->lock);
@@ -1334,7 +1323,7 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
EnterCriticalSection(&This->lock);
- if((err = snd_pcm_hw_params_any(This->pcm_handle, This->hw_params)) < 0){
+ if((err = snd_pcm_hw_params_any(This->stream->pcm_handle, This->stream->hw_params)) < 0){
hr = AUDCLNT_E_DEVICE_INVALIDATED;
goto exit;
}
@@ -1346,7 +1335,7 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
goto exit;
}
- snd_pcm_hw_params_get_format_mask(This->hw_params, formats);
+ snd_pcm_hw_params_get_format_mask(This->stream->hw_params, formats);
format = alsa_format(fmt);
if (format == SND_PCM_FORMAT_UNKNOWN ||
!snd_pcm_format_mask_test(formats, format)){
@@ -1360,13 +1349,13 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
goto exit;
}
- if((err = snd_pcm_hw_params_get_rate_min(This->hw_params, &min, NULL)) < 0){
+ if((err = snd_pcm_hw_params_get_rate_min(This->stream->hw_params, &min, NULL)) < 0){
hr = AUDCLNT_E_DEVICE_INVALIDATED;
WARN("Unable to get min rate: %d (%s)\n", err, snd_strerror(err));
goto exit;
}
- if((err = snd_pcm_hw_params_get_rate_max(This->hw_params, &max, NULL)) < 0){
+ if((err = snd_pcm_hw_params_get_rate_max(This->stream->hw_params, &max, NULL)) < 0){
hr = AUDCLNT_E_DEVICE_INVALIDATED;
WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err));
goto exit;
@@ -1377,13 +1366,13 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
goto exit;
}
- if((err = snd_pcm_hw_params_get_channels_min(This->hw_params, &min)) < 0){
+ if((err = snd_pcm_hw_params_get_channels_min(This->stream->hw_params, &min)) < 0){
hr = AUDCLNT_E_DEVICE_INVALIDATED;
WARN("Unable to get min channels: %d (%s)\n", err, snd_strerror(err));
goto exit;
}
- if((err = snd_pcm_hw_params_get_channels_max(This->hw_params, &max)) < 0){
+ if((err = snd_pcm_hw_params_get_channels_max(This->stream->hw_params, &max)) < 0){
hr = AUDCLNT_E_DEVICE_INVALIDATED;
WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err));
goto exit;
@@ -1469,13 +1458,13 @@ static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
EnterCriticalSection(&This->lock);
- if((err = snd_pcm_hw_params_any(This->pcm_handle, This->hw_params)) < 0){
+ if((err = snd_pcm_hw_params_any(This->stream->pcm_handle, This->stream->hw_params)) < 0){
WARN("Unable to get hw_params: %d (%s)\n", err, snd_strerror(err));
hr = AUDCLNT_E_DEVICE_INVALIDATED;
goto exit;
}
- snd_pcm_hw_params_get_format_mask(This->hw_params, formats);
+ snd_pcm_hw_params_get_format_mask(This->stream->hw_params, formats);
fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_FLOAT_LE)){
@@ -1499,7 +1488,7 @@ static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
goto exit;
}
- if((err = snd_pcm_hw_params_get_channels_max(This->hw_params,
+ if((err = snd_pcm_hw_params_get_channels_max(This->stream->hw_params,
&max_channels)) < 0){
WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err));
hr = AUDCLNT_E_DEVICE_INVALIDATED;
@@ -1529,7 +1518,7 @@ static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
- if((err = snd_pcm_hw_params_get_rate_max(This->hw_params, &max_rate,
+ if((err = snd_pcm_hw_params_get_rate_max(This->stream->hw_params, &max_rate,
NULL)) < 0){
WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err));
hr = AUDCLNT_E_DEVICE_INVALIDATED;
@@ -1590,97 +1579,98 @@ static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface,
return S_OK;
}
-static BYTE *remap_channels(ACImpl *This, BYTE *buf, snd_pcm_uframes_t frames)
+static BYTE *remap_channels(struct alsa_stream *stream, BYTE *buf, snd_pcm_uframes_t frames)
{
snd_pcm_uframes_t i;
UINT c;
- UINT bytes_per_sample = This->fmt->wBitsPerSample / 8;
+ UINT bytes_per_sample = stream->fmt->wBitsPerSample / 8;
- if(!This->need_remapping)
+ if(!stream->need_remapping)
return buf;
- if(!This->remapping_buf){
- This->remapping_buf = HeapAlloc(GetProcessHeap(), 0,
- bytes_per_sample * This->alsa_channels * frames);
- This->remapping_buf_frames = frames;
- }else if(This->remapping_buf_frames < frames){
- This->remapping_buf = HeapReAlloc(GetProcessHeap(), 0, This->remapping_buf,
- bytes_per_sample * This->alsa_channels * frames);
- This->remapping_buf_frames = frames;
+ if(!stream->remapping_buf){
+ stream->remapping_buf = HeapAlloc(GetProcessHeap(), 0,
+ bytes_per_sample * stream->alsa_channels * frames);
+ stream->remapping_buf_frames = frames;
+ }else if(stream->remapping_buf_frames < frames){
+ stream->remapping_buf = HeapReAlloc(GetProcessHeap(), 0, stream->remapping_buf,
+ bytes_per_sample * stream->alsa_channels * frames);
+ stream->remapping_buf_frames = frames;
}
- snd_pcm_format_set_silence(This->alsa_format, This->remapping_buf,
- frames * This->alsa_channels);
+ snd_pcm_format_set_silence(stream->alsa_format, stream->remapping_buf,
+ frames * stream->alsa_channels);
- switch(This->fmt->wBitsPerSample){
+ switch(stream->fmt->wBitsPerSample){
case 8: {
UINT8 *tgt_buf, *src_buf;
- tgt_buf = This->remapping_buf;
+ tgt_buf = stream->remapping_buf;
src_buf = buf;
for(i = 0; i < frames; ++i){
- for(c = 0; c < This->fmt->nChannels; ++c)
- tgt_buf[This->alsa_channel_map[c]] = src_buf[c];
- tgt_buf += This->alsa_channels;
- src_buf += This->fmt->nChannels;
+ for(c = 0; c < stream->fmt->nChannels; ++c)
+ tgt_buf[stream->alsa_channel_map[c]] = src_buf[c];
+ tgt_buf += stream->alsa_channels;
+ src_buf += stream->fmt->nChannels;
}
break;
}
case 16: {
UINT16 *tgt_buf, *src_buf;
- tgt_buf = (UINT16*)This->remapping_buf;
+ tgt_buf = (UINT16*)stream->remapping_buf;
src_buf = (UINT16*)buf;
for(i = 0; i < frames; ++i){
- for(c = 0; c < This->fmt->nChannels; ++c)
- tgt_buf[This->alsa_channel_map[c]] = src_buf[c];
- tgt_buf += This->alsa_channels;
- src_buf += This->fmt->nChannels;
+ for(c = 0; c < stream->fmt->nChannels; ++c)
+ tgt_buf[stream->alsa_channel_map[c]] = src_buf[c];
+ tgt_buf += stream->alsa_channels;
+ src_buf += stream->fmt->nChannels;
}
}
break;
case 32: {
UINT32 *tgt_buf, *src_buf;
- tgt_buf = (UINT32*)This->remapping_buf;
+ tgt_buf = (UINT32*)stream->remapping_buf;
src_buf = (UINT32*)buf;
for(i = 0; i < frames; ++i){
- for(c = 0; c < This->fmt->nChannels; ++c)
- tgt_buf[This->alsa_channel_map[c]] = src_buf[c];
- tgt_buf += This->alsa_channels;
- src_buf += This->fmt->nChannels;
+ for(c = 0; c < stream->fmt->nChannels; ++c)
+ tgt_buf[stream->alsa_channel_map[c]] = src_buf[c];
+ tgt_buf += stream->alsa_channels;
+ src_buf += stream->fmt->nChannels;
}
}
break;
default: {
BYTE *tgt_buf, *src_buf;
- tgt_buf = This->remapping_buf;
+ tgt_buf = stream->remapping_buf;
src_buf = buf;
for(i = 0; i < frames; ++i){
- for(c = 0; c < This->fmt->nChannels; ++c)
- memcpy(&tgt_buf[This->alsa_channel_map[c] * bytes_per_sample],
+ for(c = 0; c < stream->fmt->nChannels; ++c)
+ memcpy(&tgt_buf[stream->alsa_channel_map[c] * bytes_per_sample],
&src_buf[c * bytes_per_sample], bytes_per_sample);
- tgt_buf += This->alsa_channels * bytes_per_sample;
- src_buf += This->fmt->nChannels * bytes_per_sample;
+ tgt_buf += stream->alsa_channels * bytes_per_sample;
+ src_buf += stream->fmt->nChannels * bytes_per_sample;
}
}
break;
}
- return This->remapping_buf;
+ return stream->remapping_buf;
}
static void adjust_buffer_volume(const ACImpl *This, BYTE *buf, snd_pcm_uframes_t frames, BOOL mute)
{
- float vol[ARRAY_SIZE(This->alsa_channel_map)];
+ struct alsa_stream *stream = This->stream;
+ float vol[ARRAY_SIZE(stream->alsa_channel_map)];
BOOL adjust = FALSE;
UINT32 i, channels;
BYTE *end;
- if (This->vol_adjusted_frames >= frames)
+ if (stream->vol_adjusted_frames >= frames)
return;
- channels = This->fmt->nChannels;
+ channels = stream->fmt->nChannels;
if (mute)
{
- int err = snd_pcm_format_set_silence(This->alsa_format, buf, frames * channels);
+ int err = snd_pcm_format_set_silence(stream->alsa_format, buf, frames * channels);
if (err < 0)
WARN("Setting buffer to silence failed: %d (%s)\n", err, snd_strerror(err));
return;
@@ -1698,10 +1688,10 @@ static void adjust_buffer_volume(const ACImpl *This, BYTE *buf, snd_pcm_uframes_
if (!adjust) return;
/* Skip the frames we've already adjusted before */
- end = buf + frames * This->fmt->nBlockAlign;
- buf += This->vol_adjusted_frames * This->fmt->nBlockAlign;
+ end = buf + frames * stream->fmt->nBlockAlign;
+ buf += stream->vol_adjusted_frames * stream->fmt->nBlockAlign;
- switch (This->alsa_format)
+ switch (stream->alsa_format)
{
#ifndef WORDS_BIGENDIAN
#define PROCESS_BUFFER(type) do \
@@ -1735,7 +1725,7 @@ static void adjust_buffer_volume(const ACImpl *This, BYTE *buf, snd_pcm_uframes_
BYTE *p;
/* After we adjust the volume, we need to mask out low bits */
- if (This->alsa_format == SND_PCM_FORMAT_S20_3LE)
+ if (stream->alsa_format == SND_PCM_FORMAT_S20_3LE)
mask = ~0x0fff;
i = 0;
@@ -1781,7 +1771,7 @@ static void adjust_buffer_volume(const ACImpl *This, BYTE *buf, snd_pcm_uframes_
break;
}
default:
- TRACE("Unhandled format %i, not adjusting volume.\n", This->alsa_format);
+ TRACE("Unhandled format %i, not adjusting volume.\n", stream->alsa_format);
break;
}
}
@@ -1789,17 +1779,18 @@ static void adjust_buffer_volume(const ACImpl *This, BYTE *buf, snd_pcm_uframes_
static snd_pcm_sframes_t alsa_write_best_effort(ACImpl *This, BYTE *buf,
snd_pcm_uframes_t frames, BOOL mute)
{
+ struct alsa_stream *stream = This->stream;
snd_pcm_sframes_t written;
adjust_buffer_volume(This, buf, frames, mute);
/* Mark the frames we've already adjusted */
- if (This->vol_adjusted_frames < frames)
- This->vol_adjusted_frames = frames;
+ if (stream->vol_adjusted_frames < frames)
+ stream->vol_adjusted_frames = frames;
- buf = remap_channels(This, buf, frames);
+ buf = remap_channels(stream, buf, frames);
- written = snd_pcm_writei(This->pcm_handle, buf, frames);
+ written = snd_pcm_writei(stream->pcm_handle, buf, frames);
if(written < 0){
int ret;
@@ -1810,17 +1801,17 @@ static snd_pcm_sframes_t alsa_write_best_effort(ACImpl *This, BYTE *buf,
WARN("writei failed, recovering: %ld (%s)\n", written,
snd_strerror(written));
- ret = snd_pcm_recover(This->pcm_handle, written, 0);
+ ret = snd_pcm_recover(stream->pcm_handle, written, 0);
if(ret < 0){
WARN("Could not recover: %d (%s)\n", ret, snd_strerror(ret));
return ret;
}
- written = snd_pcm_writei(This->pcm_handle, buf, frames);
+ written = snd_pcm_writei(stream->pcm_handle, buf, frames);
}
if (written > 0)
- This->vol_adjusted_frames -= written;
+ stream->vol_adjusted_frames -= written;
return written;
}
@@ -1828,6 +1819,7 @@ static snd_pcm_sframes_t alsa_write_buffer_wrap(ACImpl *This, BYTE *buf,
snd_pcm_uframes_t buflen, snd_pcm_uframes_t offs,
snd_pcm_uframes_t to_write)
{
+ struct alsa_stream *stream = This->stream;
snd_pcm_sframes_t ret = 0;
while(to_write){
@@ -1839,7 +1831,7 @@ static snd_pcm_sframes_t alsa_write_buffer_wrap(ACImpl *This, BYTE *buf,
else
chunk = to_write;
- tmp = alsa_write_best_effort(This, buf + offs * This->fmt->nBlockAlign, chunk, This->session->mute);
+ tmp = alsa_write_best_effort(This, buf + offs * stream->fmt->nBlockAlign, chunk, This->session->mute);
if(tmp < 0)
return ret;
if(!tmp)
@@ -1863,13 +1855,14 @@ static UINT buf_ptr_diff(UINT left, UINT right, UINT bufsize)
static UINT data_not_in_alsa(ACImpl *This)
{
+ struct alsa_stream *stream = This->stream;
UINT32 diff;
- diff = buf_ptr_diff(This->lcl_offs_frames, This->wri_offs_frames, This->bufsize_frames);
+ diff = buf_ptr_diff(stream->lcl_offs_frames, stream->wri_offs_frames, stream->bufsize_frames);
if(diff)
return diff;
- return This->held_frames - This->data_in_alsa_frames;
+ return stream->held_frames - stream->data_in_alsa_frames;
}
/* Here's the buffer setup:
*
@@ -1891,25 +1884,26 @@ static UINT data_not_in_alsa(ACImpl *This)
*/
static void alsa_write_data(ACImpl *This)
{
+ struct alsa_stream *stream = This->stream;
snd_pcm_sframes_t written;
snd_pcm_uframes_t avail, max_copy_frames, data_frames_played;
int err;
/* this call seems to be required to get an accurate snd_pcm_state() */
- avail = snd_pcm_avail_update(This->pcm_handle);
+ avail = snd_pcm_avail_update(stream->pcm_handle);
- if(snd_pcm_state(This->pcm_handle) == SND_PCM_STATE_XRUN){
+ if(snd_pcm_state(stream->pcm_handle) == SND_PCM_STATE_XRUN){
TRACE("XRun state, recovering\n");
- avail = This->alsa_bufsize_frames;
+ avail = stream->alsa_bufsize_frames;
- if((err = snd_pcm_recover(This->pcm_handle, -EPIPE, 1)) < 0)
+ if((err = snd_pcm_recover(stream->pcm_handle, -EPIPE, 1)) < 0)
WARN("snd_pcm_recover failed: %d (%s)\n", err, snd_strerror(err));
- if((err = snd_pcm_reset(This->pcm_handle)) < 0)
+ if((err = snd_pcm_reset(stream->pcm_handle)) < 0)
WARN("snd_pcm_reset failed: %d (%s)\n", err, snd_strerror(err));
- if((err = snd_pcm_prepare(This->pcm_handle)) < 0)
+ if((err = snd_pcm_prepare(stream->pcm_handle)) < 0)
WARN("snd_pcm_prepare failed: %d (%s)\n", err, snd_strerror(err));
}
@@ -1917,61 +1911,63 @@ static void alsa_write_data(ACImpl *This)
/* Add a lead-in when starting with too few frames to ensure
* continuous rendering. Additional benefit: Force ALSA to start. */
- if(This->data_in_alsa_frames == 0 && This->held_frames < This->alsa_period_frames)
+ if(stream->data_in_alsa_frames == 0 && stream->held_frames < stream->alsa_period_frames)
{
- alsa_write_best_effort(This, This->silence_buf, This->alsa_period_frames - This->held_frames, FALSE);
- This->vol_adjusted_frames = 0;
+ alsa_write_best_effort(This, stream->silence_buf,
+ stream->alsa_period_frames - stream->held_frames, FALSE);
+ stream->vol_adjusted_frames = 0;
}
- if(This->started)
+ if(stream->started)
max_copy_frames = data_not_in_alsa(This);
else
max_copy_frames = 0;
- data_frames_played = min(This->data_in_alsa_frames, avail);
- This->data_in_alsa_frames -= data_frames_played;
+ data_frames_played = min(stream->data_in_alsa_frames, avail);
+ stream->data_in_alsa_frames -= data_frames_played;
- if(This->held_frames > data_frames_played){
- if(This->started)
- This->held_frames -= data_frames_played;
+ if(stream->held_frames > data_frames_played){
+ if(stream->started)
+ stream->held_frames -= data_frames_played;
}else
- This->held_frames = 0;
+ stream->held_frames = 0;
while(avail && max_copy_frames){
snd_pcm_uframes_t to_write;
to_write = min(avail, max_copy_frames);
- written = alsa_write_buffer_wrap(This, This->local_buffer,
- This->bufsize_frames, This->lcl_offs_frames, to_write);
+ written = alsa_write_buffer_wrap(This, stream->local_buffer,
+ stream->bufsize_frames, stream->lcl_offs_frames, to_write);
if(written <= 0)
break;
avail -= written;
- This->lcl_offs_frames += written;
- This->lcl_offs_frames %= This->bufsize_frames;
- This->data_in_alsa_frames += written;
+ stream->lcl_offs_frames += written;
+ stream->lcl_offs_frames %= stream->bufsize_frames;
+ stream->data_in_alsa_frames += written;
max_copy_frames -= written;
}
- if(This->event)
- SetEvent(This->event);
+ if(stream->event)
+ SetEvent(stream->event);
}
static void alsa_read_data(ACImpl *This)
{
+ struct alsa_stream *stream = This->stream;
snd_pcm_sframes_t nread;
- UINT32 pos = This->wri_offs_frames, limit = This->held_frames;
+ UINT32 pos = stream->wri_offs_frames, limit = stream->held_frames;
- if(!This->started)
+ if(!stream->started)
goto exit;
/* FIXME: Detect overrun and signal DATA_DISCONTINUITY
* How to count overrun frames and report them as position increase? */
- limit = This->bufsize_frames - max(limit, pos);
+ limit = stream->bufsize_frames - max(limit, pos);
- nread = snd_pcm_readi(This->pcm_handle,
- This->local_buffer + pos * This->fmt->nBlockAlign, limit);
+ nread = snd_pcm_readi(stream->pcm_handle,
+ stream->local_buffer + pos * stream->fmt->nBlockAlign, limit);
TRACE("read %ld from %u limit %u\n", nread, pos, limit);
if(nread < 0){
int ret;
@@ -1981,14 +1977,14 @@ static void alsa_read_data(ACImpl *This)
WARN("read failed, recovering: %ld (%s)\n", nread, snd_strerror(nread));
- ret = snd_pcm_recover(This->pcm_handle, nread, 0);
+ ret = snd_pcm_recover(stream->pcm_handle, nread, 0);
if(ret < 0){
WARN("Recover failed: %d (%s)\n", ret, snd_strerror(ret));
return;
}
- nread = snd_pcm_readi(This->pcm_handle,
- This->local_buffer + pos * This->fmt->nBlockAlign, limit);
+ nread = snd_pcm_readi(stream->pcm_handle,
+ stream->local_buffer + pos * stream->fmt->nBlockAlign, limit);
if(nread < 0){
WARN("read failed: %ld (%s)\n", nread, snd_strerror(nread));
return;
@@ -1997,29 +1993,30 @@ static void alsa_read_data(ACImpl *This)
if(This->session->mute){
int err;
- if((err = snd_pcm_format_set_silence(This->alsa_format,
- This->local_buffer + pos * This->fmt->nBlockAlign,
+ if((err = snd_pcm_format_set_silence(stream->alsa_format,
+ stream->local_buffer + pos * stream->fmt->nBlockAlign,
nread)) < 0)
WARN("Setting buffer to silence failed: %d (%s)\n", err,
snd_strerror(err));
}
- This->wri_offs_frames += nread;
- This->wri_offs_frames %= This->bufsize_frames;
- This->held_frames += nread;
+ stream->wri_offs_frames += nread;
+ stream->wri_offs_frames %= stream->bufsize_frames;
+ stream->held_frames += nread;
exit:
- if(This->event)
- SetEvent(This->event);
+ if(stream->event)
+ SetEvent(stream->event);
}
static void CALLBACK alsa_push_buffer_data(void *user, BOOLEAN timer)
{
ACImpl *This = user;
+ struct alsa_stream *stream = This->stream;
EnterCriticalSection(&This->lock);
- QueryPerformanceCounter(&This->last_period_time);
+ QueryPerformanceCounter(&stream->last_period_time);
if(This->dataflow == eRender)
alsa_write_data(This);
@@ -2029,17 +2026,18 @@ static void CALLBACK alsa_push_buffer_data(void *user, BOOLEAN timer)
LeaveCriticalSection(&This->lock);
}
-static snd_pcm_uframes_t interp_elapsed_frames(ACImpl *This)
+static snd_pcm_uframes_t interp_elapsed_frames(struct alsa_stream *stream)
{
LARGE_INTEGER time_freq, current_time, time_diff;
QueryPerformanceFrequency(&time_freq);
QueryPerformanceCounter(¤t_time);
- time_diff.QuadPart = current_time.QuadPart - This->last_period_time.QuadPart;
- return MulDiv(time_diff.QuadPart, This->fmt->nSamplesPerSec, time_freq.QuadPart);
+ time_diff.QuadPart = current_time.QuadPart - stream->last_period_time.QuadPart;
+ return MulDiv(time_diff.QuadPart, stream->fmt->nSamplesPerSec, time_freq.QuadPart);
}
static int alsa_rewind_best_effort(ACImpl *This)
{
+ struct alsa_stream *stream = This->stream;
snd_pcm_uframes_t len, leave;
/* we can't use snd_pcm_rewindable, some PCM devices crash. so follow
@@ -2047,25 +2045,25 @@ static int alsa_rewind_best_effort(ACImpl *This)
* buffer, minus 1.33ms for safety. */
/* amount of data to leave in ALSA buffer */
- leave = interp_elapsed_frames(This) + This->safe_rewind_frames;
+ leave = interp_elapsed_frames(stream) + stream->safe_rewind_frames;
- if(This->held_frames < leave)
- This->held_frames = 0;
+ if(stream->held_frames < leave)
+ stream->held_frames = 0;
else
- This->held_frames -= leave;
+ stream->held_frames -= leave;
- if(This->data_in_alsa_frames < leave)
+ if(stream->data_in_alsa_frames < leave)
len = 0;
else
- len = This->data_in_alsa_frames - leave;
+ len = stream->data_in_alsa_frames - leave;
- TRACE("rewinding %lu frames, now held %u\n", len, This->held_frames);
+ TRACE("rewinding %lu frames, now held %u\n", len, stream->held_frames);
if(len)
/* snd_pcm_rewind return value is often broken, assume it succeeded */
- snd_pcm_rewind(This->pcm_handle, len);
+ snd_pcm_rewind(stream->pcm_handle, len);
- This->data_in_alsa_frames = 0;
+ stream->data_in_alsa_frames = 0;
return len;
}
@@ -2073,6 +2071,7 @@ static int alsa_rewind_best_effort(ACImpl *This)
static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
{
ACImpl *This = impl_from_IAudioClient3(iface);
+ struct alsa_stream *stream = This->stream;
TRACE("(%p)\n", This);
@@ -2083,55 +2082,55 @@ static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
return AUDCLNT_E_NOT_INITIALIZED;
}
- if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
+ if((stream->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !stream->event){
LeaveCriticalSection(&This->lock);
return AUDCLNT_E_EVENTHANDLE_NOT_SET;
}
- if(This->started){
+ if(stream->started){
LeaveCriticalSection(&This->lock);
return AUDCLNT_E_NOT_STOPPED;
}
if(This->dataflow == eCapture){
/* dump any data that might be leftover in the ALSA capture buffer */
- snd_pcm_readi(This->pcm_handle, This->local_buffer,
- This->bufsize_frames);
+ snd_pcm_readi(stream->pcm_handle, stream->local_buffer,
+ stream->bufsize_frames);
}else{
snd_pcm_sframes_t avail, written;
snd_pcm_uframes_t offs;
- avail = snd_pcm_avail_update(This->pcm_handle);
- avail = min(avail, This->held_frames);
+ avail = snd_pcm_avail_update(stream->pcm_handle);
+ avail = min(avail, stream->held_frames);
- if(This->wri_offs_frames < This->held_frames)
- offs = This->bufsize_frames - This->held_frames + This->wri_offs_frames;
+ if(stream->wri_offs_frames < stream->held_frames)
+ offs = stream->bufsize_frames - stream->held_frames + stream->wri_offs_frames;
else
- offs = This->wri_offs_frames - This->held_frames;
+ offs = stream->wri_offs_frames - stream->held_frames;
/* fill it with data */
- written = alsa_write_buffer_wrap(This, This->local_buffer,
- This->bufsize_frames, offs, avail);
+ written = alsa_write_buffer_wrap(This, stream->local_buffer,
+ stream->bufsize_frames, offs, avail);
if(written > 0){
- This->lcl_offs_frames = (offs + written) % This->bufsize_frames;
- This->data_in_alsa_frames = written;
+ stream->lcl_offs_frames = (offs + written) % stream->bufsize_frames;
+ stream->data_in_alsa_frames = written;
}else{
- This->lcl_offs_frames = offs;
- This->data_in_alsa_frames = 0;
+ stream->lcl_offs_frames = offs;
+ stream->data_in_alsa_frames = 0;
}
}
if(!This->timer){
if(!CreateTimerQueueTimer(&This->timer, g_timer_q, alsa_push_buffer_data,
- This, 0, This->mmdev_period_rt / 10000, WT_EXECUTEINTIMERTHREAD)){
+ This, 0, stream->mmdev_period_rt / 10000, WT_EXECUTEINTIMERTHREAD)){
LeaveCriticalSection(&This->lock);
WARN("Unable to create timer: %u\n", GetLastError());
return E_OUTOFMEMORY;
}
}
- This->started = TRUE;
+ stream->started = TRUE;
LeaveCriticalSection(&This->lock);
@@ -2141,6 +2140,7 @@ static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
{
ACImpl *This = impl_from_IAudioClient3(iface);
+ struct alsa_stream *stream = This->stream;
TRACE("(%p)\n", This);
@@ -2151,7 +2151,7 @@ static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
return AUDCLNT_E_NOT_INITIALIZED;
}
- if(!This->started){
+ if(!stream->started){
LeaveCriticalSection(&This->lock);
return S_FALSE;
}
@@ -2159,7 +2159,7 @@ static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
if(This->dataflow == eRender)
alsa_rewind_best_effort(This);
- This->started = FALSE;
+ stream->started = FALSE;
LeaveCriticalSection(&This->lock);
@@ -2169,6 +2169,7 @@ static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface)
{
ACImpl *This = impl_from_IAudioClient3(iface);
+ struct alsa_stream *stream = This->stream;
TRACE("(%p)\n", This);
@@ -2179,34 +2180,34 @@ static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface)
return AUDCLNT_E_NOT_INITIALIZED;
}
- if(This->started){
+ if(stream->started){
LeaveCriticalSection(&This->lock);
return AUDCLNT_E_NOT_STOPPED;
}
- if(This->getbuf_last){
+ if(stream->getbuf_last){
LeaveCriticalSection(&This->lock);
return AUDCLNT_E_BUFFER_OPERATION_PENDING;
}
- if(snd_pcm_drop(This->pcm_handle) < 0)
+ if(snd_pcm_drop(stream->pcm_handle) < 0)
WARN("snd_pcm_drop failed\n");
- if(snd_pcm_reset(This->pcm_handle) < 0)
+ if(snd_pcm_reset(stream->pcm_handle) < 0)
WARN("snd_pcm_reset failed\n");
- if(snd_pcm_prepare(This->pcm_handle) < 0)
+ if(snd_pcm_prepare(stream->pcm_handle) < 0)
WARN("snd_pcm_prepare failed\n");
if(This->dataflow == eRender){
- This->written_frames = 0;
- This->last_pos_frames = 0;
+ stream->written_frames = 0;
+ stream->last_pos_frames = 0;
}else{
- This->written_frames += This->held_frames;
+ stream->written_frames += stream->held_frames;
}
- This->held_frames = 0;
- This->lcl_offs_frames = 0;
- This->wri_offs_frames = 0;
+ stream->held_frames = 0;
+ stream->lcl_offs_frames = 0;
+ stream->wri_offs_frames = 0;
LeaveCriticalSection(&This->lock);
@@ -2217,6 +2218,7 @@ static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
HANDLE event)
{
ACImpl *This = impl_from_IAudioClient3(iface);
+ struct alsa_stream *stream = This->stream;
TRACE("(%p)->(%p)\n", This, event);
@@ -2230,18 +2232,18 @@ static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
return AUDCLNT_E_NOT_INITIALIZED;
}
- if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
+ if(!(stream->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
LeaveCriticalSection(&This->lock);
return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
}
- if (This->event){
+ if (stream->event){
LeaveCriticalSection(&This->lock);
FIXME("called twice\n");
return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
}
- This->event = event;
+ stream->event = event;
LeaveCriticalSection(&This->lock);
@@ -2489,6 +2491,7 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
UINT32 frames, BYTE **data)
{
ACImpl *This = impl_from_IAudioRenderClient(iface);
+ struct alsa_stream *stream = This->stream;
UINT32 write_pos;
TRACE("(%p)->(%u, %p)\n", This, frames, data);
@@ -2499,7 +2502,7 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
EnterCriticalSection(&This->lock);
- if(This->getbuf_last){
+ if(stream->getbuf_last){
LeaveCriticalSection(&This->lock);
return AUDCLNT_E_OUT_OF_ORDER;
}
@@ -2510,50 +2513,50 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
}
/* held_frames == GetCurrentPadding_nolock(); */
- if(This->held_frames + frames > This->bufsize_frames){
+ if(stream->held_frames + frames > stream->bufsize_frames){
LeaveCriticalSection(&This->lock);
return AUDCLNT_E_BUFFER_TOO_LARGE;
}
- write_pos = This->wri_offs_frames;
- if(write_pos + frames > This->bufsize_frames){
- if(This->tmp_buffer_frames < frames){
- HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
- This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
- frames * This->fmt->nBlockAlign);
- if(!This->tmp_buffer){
+ write_pos = stream->wri_offs_frames;
+ if(write_pos + frames > stream->bufsize_frames){
+ if(stream->tmp_buffer_frames < frames){
+ HeapFree(GetProcessHeap(), 0, stream->tmp_buffer);
+ stream->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
+ frames * stream->fmt->nBlockAlign);
+ if(!stream->tmp_buffer){
LeaveCriticalSection(&This->lock);
return E_OUTOFMEMORY;
}
- This->tmp_buffer_frames = frames;
+ stream->tmp_buffer_frames = frames;
}
- *data = This->tmp_buffer;
- This->getbuf_last = -frames;
+ *data = stream->tmp_buffer;
+ stream->getbuf_last = -frames;
}else{
- *data = This->local_buffer + write_pos * This->fmt->nBlockAlign;
- This->getbuf_last = frames;
+ *data = stream->local_buffer + write_pos * stream->fmt->nBlockAlign;
+ stream->getbuf_last = frames;
}
- silence_buffer(This, *data, frames);
+ silence_buffer(stream, *data, frames);
LeaveCriticalSection(&This->lock);
return S_OK;
}
-static void alsa_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_frames)
+static void alsa_wrap_buffer(struct alsa_stream *stream, BYTE *buffer, UINT32 written_frames)
{
- snd_pcm_uframes_t write_offs_frames = This->wri_offs_frames;
- UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
- snd_pcm_uframes_t chunk_frames = This->bufsize_frames - write_offs_frames;
- UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
- UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
+ snd_pcm_uframes_t write_offs_frames = stream->wri_offs_frames;
+ UINT32 write_offs_bytes = write_offs_frames * stream->fmt->nBlockAlign;
+ snd_pcm_uframes_t chunk_frames = stream->bufsize_frames - write_offs_frames;
+ UINT32 chunk_bytes = chunk_frames * stream->fmt->nBlockAlign;
+ UINT32 written_bytes = written_frames * stream->fmt->nBlockAlign;
if(written_bytes <= chunk_bytes){
- memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
+ memcpy(stream->local_buffer + write_offs_bytes, buffer, written_bytes);
}else{
- memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
- memcpy(This->local_buffer, buffer + chunk_bytes,
+ memcpy(stream->local_buffer + write_offs_bytes, buffer, chunk_bytes);
+ memcpy(stream->local_buffer, buffer + chunk_bytes,
written_bytes - chunk_bytes);
}
}
@@ -2562,6 +2565,7 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
{
ACImpl *This = impl_from_IAudioRenderClient(iface);
+ struct alsa_stream *stream = This->stream;
BYTE *buffer;
TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
@@ -2569,37 +2573,37 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
EnterCriticalSection(&This->lock);
if(!written_frames){
- This->getbuf_last = 0;
+ stream->getbuf_last = 0;
LeaveCriticalSection(&This->lock);
return S_OK;
}
- if(!This->getbuf_last){
+ if(!stream->getbuf_last){
LeaveCriticalSection(&This->lock);
return AUDCLNT_E_OUT_OF_ORDER;
}
- if(written_frames > (This->getbuf_last >= 0 ? This->getbuf_last : -This->getbuf_last)){
+ if(written_frames > (stream->getbuf_last >= 0 ? stream->getbuf_last : -stream->getbuf_last)){
LeaveCriticalSection(&This->lock);
return AUDCLNT_E_INVALID_SIZE;
}
- if(This->getbuf_last >= 0)
- buffer = This->local_buffer + This->wri_offs_frames * This->fmt->nBlockAlign;
+ if(stream->getbuf_last >= 0)
+ buffer = stream->local_buffer + stream->wri_offs_frames * stream->fmt->nBlockAlign;
else
- buffer = This->tmp_buffer;
+ buffer = stream->tmp_buffer;
if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
- silence_buffer(This, buffer, written_frames);
+ silence_buffer(stream, buffer, written_frames);
- if(This->getbuf_last < 0)
- alsa_wrap_buffer(This, buffer, written_frames);
+ if(stream->getbuf_last < 0)
+ alsa_wrap_buffer(stream, buffer, written_frames);
- This->wri_offs_frames += written_frames;
- This->wri_offs_frames %= This->bufsize_frames;
- This->held_frames += written_frames;
- This->written_frames += written_frames;
- This->getbuf_last = 0;
+ stream->wri_offs_frames += written_frames;
+ stream->wri_offs_frames %= stream->bufsize_frames;
+ stream->held_frames += written_frames;
+ stream->written_frames += written_frames;
+ stream->getbuf_last = 0;
LeaveCriticalSection(&This->lock);
@@ -2656,6 +2660,7 @@ static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
UINT64 *qpcpos)
{
ACImpl *This = impl_from_IAudioCaptureClient(iface);
+ struct alsa_stream *stream = This->stream;
TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
devpos, qpcpos);
@@ -2670,49 +2675,49 @@ static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
EnterCriticalSection(&This->lock);
- if(This->getbuf_last){
+ if(stream->getbuf_last){
LeaveCriticalSection(&This->lock);
return AUDCLNT_E_OUT_OF_ORDER;
}
/* hr = GetNextPacketSize(iface, frames); */
- if(This->held_frames < This->mmdev_period_frames){
+ if(stream->held_frames < stream->mmdev_period_frames){
*frames = 0;
LeaveCriticalSection(&This->lock);
return AUDCLNT_S_BUFFER_EMPTY;
}
- *frames = This->mmdev_period_frames;
+ *frames = stream->mmdev_period_frames;
- if(This->lcl_offs_frames + *frames > This->bufsize_frames){
+ if(stream->lcl_offs_frames + *frames > stream->bufsize_frames){
UINT32 chunk_bytes, offs_bytes, frames_bytes;
- if(This->tmp_buffer_frames < *frames){
- HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
- This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
- *frames * This->fmt->nBlockAlign);
- if(!This->tmp_buffer){
+ if(stream->tmp_buffer_frames < *frames){
+ HeapFree(GetProcessHeap(), 0, stream->tmp_buffer);
+ stream->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
+ *frames * stream->fmt->nBlockAlign);
+ if(!stream->tmp_buffer){
LeaveCriticalSection(&This->lock);
return E_OUTOFMEMORY;
}
- This->tmp_buffer_frames = *frames;
+ stream->tmp_buffer_frames = *frames;
}
- *data = This->tmp_buffer;
- chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
- This->fmt->nBlockAlign;
- offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
- frames_bytes = *frames * This->fmt->nBlockAlign;
- memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
- memcpy(This->tmp_buffer + chunk_bytes, This->local_buffer,
+ *data = stream->tmp_buffer;
+ chunk_bytes = (stream->bufsize_frames - stream->lcl_offs_frames) *
+ stream->fmt->nBlockAlign;
+ offs_bytes = stream->lcl_offs_frames * stream->fmt->nBlockAlign;
+ frames_bytes = *frames * stream->fmt->nBlockAlign;
+ memcpy(stream->tmp_buffer, stream->local_buffer + offs_bytes, chunk_bytes);
+ memcpy(stream->tmp_buffer + chunk_bytes, stream->local_buffer,
frames_bytes - chunk_bytes);
}else
- *data = This->local_buffer +
- This->lcl_offs_frames * This->fmt->nBlockAlign;
+ *data = stream->local_buffer +
+ stream->lcl_offs_frames * stream->fmt->nBlockAlign;
- This->getbuf_last = *frames;
+ stream->getbuf_last = *frames;
*flags = 0;
if(devpos)
- *devpos = This->written_frames;
+ *devpos = stream->written_frames;
if(qpcpos){ /* fixme: qpc of recording time */
LARGE_INTEGER stamp, freq;
QueryPerformanceCounter(&stamp);
@@ -2729,32 +2734,33 @@ static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
IAudioCaptureClient *iface, UINT32 done)
{
ACImpl *This = impl_from_IAudioCaptureClient(iface);
+ struct alsa_stream *stream = This->stream;
TRACE("(%p)->(%u)\n", This, done);
EnterCriticalSection(&This->lock);
if(!done){
- This->getbuf_last = 0;
+ stream->getbuf_last = 0;
LeaveCriticalSection(&This->lock);
return S_OK;
}
- if(!This->getbuf_last){
+ if(!stream->getbuf_last){
LeaveCriticalSection(&This->lock);
return AUDCLNT_E_OUT_OF_ORDER;
}
- if(This->getbuf_last != done){
+ if(stream->getbuf_last != done){
LeaveCriticalSection(&This->lock);
return AUDCLNT_E_INVALID_SIZE;
}
- This->written_frames += done;
- This->held_frames -= done;
- This->lcl_offs_frames += done;
- This->lcl_offs_frames %= This->bufsize_frames;
- This->getbuf_last = 0;
+ stream->written_frames += done;
+ stream->held_frames -= done;
+ stream->lcl_offs_frames += done;
+ stream->lcl_offs_frames %= stream->bufsize_frames;
+ stream->getbuf_last = 0;
LeaveCriticalSection(&This->lock);
@@ -2765,6 +2771,7 @@ static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
IAudioCaptureClient *iface, UINT32 *frames)
{
ACImpl *This = impl_from_IAudioCaptureClient(iface);
+ struct alsa_stream *stream = This->stream;
TRACE("(%p)->(%p)\n", This, frames);
@@ -2773,7 +2780,7 @@ static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
EnterCriticalSection(&This->lock);
- *frames = This->held_frames < This->mmdev_period_frames ? 0 : This->mmdev_period_frames;
+ *frames = stream->held_frames < stream->mmdev_period_frames ? 0 : stream->mmdev_period_frames;
LeaveCriticalSection(&This->lock);
@@ -2829,13 +2836,14 @@ static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
{
ACImpl *This = impl_from_IAudioClock(iface);
+ struct alsa_stream *stream = This->stream;
TRACE("(%p)->(%p)\n", This, freq);
- if(This->share == AUDCLNT_SHAREMODE_SHARED)
- *freq = (UINT64)This->fmt->nSamplesPerSec * This->fmt->nBlockAlign;
+ if(stream->share == AUDCLNT_SHAREMODE_SHARED)
+ *freq = (UINT64)stream->fmt->nSamplesPerSec * stream->fmt->nBlockAlign;
else
- *freq = This->fmt->nSamplesPerSec;
+ *freq = stream->fmt->nSamplesPerSec;
return S_OK;
}
@@ -2844,6 +2852,7 @@ static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
UINT64 *qpctime)
{
ACImpl *This = impl_from_IAudioClock(iface);
+ struct alsa_stream *stream = This->stream;
UINT64 position;
snd_pcm_state_t alsa_state;
@@ -2855,38 +2864,38 @@ static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
EnterCriticalSection(&This->lock);
/* avail_update required to get accurate snd_pcm_state() */
- snd_pcm_avail_update(This->pcm_handle);
- alsa_state = snd_pcm_state(This->pcm_handle);
+ snd_pcm_avail_update(stream->pcm_handle);
+ alsa_state = snd_pcm_state(stream->pcm_handle);
if(This->dataflow == eRender){
- position = This->written_frames - This->held_frames;
+ position = stream->written_frames - stream->held_frames;
- if(This->started && alsa_state == SND_PCM_STATE_RUNNING && This->held_frames)
+ if(stream->started && alsa_state == SND_PCM_STATE_RUNNING && stream->held_frames)
/* we should be using snd_pcm_delay here, but it is broken
* especially during ALSA device underrun. instead, let's just
* interpolate between periods with the system timer. */
- position += interp_elapsed_frames(This);
+ position += interp_elapsed_frames(stream);
- position = min(position, This->written_frames - This->held_frames + This->mmdev_period_frames);
+ position = min(position, stream->written_frames - stream->held_frames + stream->mmdev_period_frames);
- position = min(position, This->written_frames);
+ position = min(position, stream->written_frames);
}else
- position = This->written_frames + This->held_frames;
+ position = stream->written_frames + stream->held_frames;
/* ensure monotic growth */
- if(position < This->last_pos_frames)
- position = This->last_pos_frames;
+ if(position < stream->last_pos_frames)
+ position = stream->last_pos_frames;
else
- This->last_pos_frames = position;
+ stream->last_pos_frames = position;
TRACE("frames written: %u, held: %u, state: 0x%x, position: %u\n",
- (UINT32)(This->written_frames%1000000000), This->held_frames,
+ (UINT32)(stream->written_frames%1000000000), stream->held_frames,
alsa_state, (UINT32)(position%1000000000));
LeaveCriticalSection(&This->lock);
- if(This->share == AUDCLNT_SHAREMODE_SHARED)
- *pos = position * This->fmt->nBlockAlign;
+ if(stream->share == AUDCLNT_SHAREMODE_SHARED)
+ *pos = position * stream->fmt->nBlockAlign;
else
*pos = position;
@@ -3056,7 +3065,7 @@ static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
EnterCriticalSection(&client->lock);
- if(client->started){
+ if(client->stream->started){
*state = AudioSessionStateActive;
LeaveCriticalSection(&client->lock);
LeaveCriticalSection(&g_sessions_lock);
diff --git a/dlls/winealsa.drv/unixlib.h b/dlls/winealsa.drv/unixlib.h
index f3014d0b448..8a20710b7e5 100644
--- a/dlls/winealsa.drv/unixlib.h
+++ b/dlls/winealsa.drv/unixlib.h
@@ -16,6 +16,41 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "audioclient.h"
+
+struct alsa_stream
+{
+ snd_pcm_t *pcm_handle;
+ snd_pcm_uframes_t alsa_bufsize_frames, alsa_period_frames, safe_rewind_frames;
+ snd_pcm_hw_params_t *hw_params; /* does not hold state between calls */
+ snd_pcm_format_t alsa_format;
+
+ LARGE_INTEGER last_period_time;
+
+ WAVEFORMATEX *fmt;
+ DWORD flags;
+ AUDCLNT_SHAREMODE share;
+ HANDLE event;
+
+ BOOL need_remapping;
+ int alsa_channels;
+ int alsa_channel_map[32];
+
+ BOOL started;
+ REFERENCE_TIME mmdev_period_rt;
+ UINT64 written_frames, last_pos_frames;
+ UINT32 bufsize_frames, held_frames, tmp_buffer_frames, mmdev_period_frames;
+ snd_pcm_uframes_t remapping_buf_frames;
+ UINT32 lcl_offs_frames; /* offs into local_buffer where valid data starts */
+ UINT32 wri_offs_frames; /* where to write fresh data in local_buffer */
+ UINT32 hidden_frames; /* ALSA reserve to ensure continuous rendering */
+ UINT32 vol_adjusted_frames; /* Frames we've already adjusted the volume of but didn't write yet */
+ UINT32 data_in_alsa_frames;
+
+ BYTE *local_buffer, *tmp_buffer, *remapping_buf, *silence_buf;
+ LONG32 getbuf_last; /* <0 when using tmp_buffer */
+};
+
struct endpoint
{
WCHAR *name;
--
2.25.1
2
1
Mainly just for simplicity.
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/winealsa.drv/mmdevdrv.c | 17 ++++++-----------
1 file changed, 6 insertions(+), 11 deletions(-)
diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c
index abec9dc969a..0549752dc3f 100644
--- a/dlls/winealsa.drv/mmdevdrv.c
+++ b/dlls/winealsa.drv/mmdevdrv.c
@@ -77,8 +77,6 @@ typedef struct _AudioSession {
float *channel_vols;
BOOL mute;
- CRITICAL_SECTION lock;
-
struct list entry;
} AudioSession;
@@ -748,9 +746,6 @@ static AudioSession *create_session(const GUID *guid, IMMDevice *device,
list_add_head(&g_sessions, &ret->entry);
- InitializeCriticalSection(&ret->lock);
- ret->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": AudioSession.lock");
-
session_init_vols(ret, num_channels);
ret->master_vol = 1.f;
@@ -3283,11 +3278,11 @@ static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
TRACE("ALSA does not support volume control\n");
- EnterCriticalSection(&session->lock);
+ EnterCriticalSection(&g_sessions_lock);
session->master_vol = level;
- LeaveCriticalSection(&session->lock);
+ LeaveCriticalSection(&g_sessions_lock);
return S_OK;
}
@@ -3573,11 +3568,11 @@ static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
TRACE("ALSA does not support volume control\n");
- EnterCriticalSection(&session->lock);
+ EnterCriticalSection(&g_sessions_lock);
session->channel_vols[index] = level;
- LeaveCriticalSection(&session->lock);
+ LeaveCriticalSection(&g_sessions_lock);
return S_OK;
}
@@ -3623,12 +3618,12 @@ static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
TRACE("ALSA does not support volume control\n");
- EnterCriticalSection(&session->lock);
+ EnterCriticalSection(&g_sessions_lock);
for(i = 0; i < count; ++i)
session->channel_vols[i] = levels[i];
- LeaveCriticalSection(&session->lock);
+ LeaveCriticalSection(&g_sessions_lock);
return S_OK;
}
--
2.25.1
2
1
[PATCH 1/8] winealsa: Explicitly store the name and channel count in the audio client.
by Huw Davies 17 Feb '22
by Huw Davies 17 Feb '22
17 Feb '22
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/winealsa.drv/mmdevdrv.c | 27 ++++++++++++++++++---------
1 file changed, 18 insertions(+), 9 deletions(-)
diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c
index 516bba1e5fc..abec9dc969a 100644
--- a/dlls/winealsa.drv/mmdevdrv.c
+++ b/dlls/winealsa.drv/mmdevdrv.c
@@ -119,6 +119,7 @@ struct ACImpl {
AUDCLNT_SHAREMODE share;
HANDLE event;
float *vols;
+ UINT32 channel_count;
BOOL need_remapping;
int alsa_channels;
@@ -145,6 +146,9 @@ struct ACImpl {
AudioSessionWrapper *session_wrapper;
struct list entry;
+
+ /* Keep at end */
+ char alsa_name[1];
};
typedef struct _SessionMgr {
@@ -472,6 +476,7 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient
char alsa_name[256];
EDataFlow dataflow;
HRESULT hr;
+ int len;
TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
@@ -481,7 +486,8 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient
if(dataflow != eRender && dataflow != eCapture)
return E_UNEXPECTED;
- This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
+ len = strlen(alsa_name);
+ This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, offsetof(ACImpl, alsa_name[len + 1]));
if(!This)
return E_OUTOFMEMORY;
@@ -499,6 +505,8 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient
}
This->dataflow = dataflow;
+ memcpy(This->alsa_name, alsa_name, len + 1);
+
err = snd_pcm_open(&This->pcm_handle, alsa_name, alsa_get_direction(dataflow), SND_PCM_NONBLOCK);
if(err < 0){
HeapFree(GetProcessHeap(), 0, This);
@@ -1159,19 +1167,20 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
}
silence_buffer(This, This->silence_buf, This->alsa_period_frames);
- This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
+ This->channel_count = fmt->nChannels;
+ This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float));
if(!This->vols){
hr = E_OUTOFMEMORY;
goto exit;
}
- for(i = 0; i < fmt->nChannels; ++i)
+ for(i = 0; i < This->channel_count; ++i)
This->vols[i] = 1.f;
This->share = mode;
This->flags = flags;
- hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
+ hr = get_audio_session(sessionguid, This->parent, This->channel_count,
&This->session);
if(FAILED(hr))
goto exit;
@@ -3385,7 +3394,7 @@ static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
if(!out)
return E_POINTER;
- *out = This->fmt->nChannels;
+ *out = This->channel_count;
return S_OK;
}
@@ -3400,7 +3409,7 @@ static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
if(level < 0.f || level > 1.f)
return E_INVALIDARG;
- if(index >= This->fmt->nChannels)
+ if(index >= This->channel_count)
return E_INVALIDARG;
TRACE("ALSA does not support volume control\n");
@@ -3424,7 +3433,7 @@ static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
if(!level)
return E_POINTER;
- if(index >= This->fmt->nChannels)
+ if(index >= This->channel_count)
return E_INVALIDARG;
*level = This->vols[index];
@@ -3443,7 +3452,7 @@ static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
if(!levels)
return E_POINTER;
- if(count != This->fmt->nChannels)
+ if(count != This->channel_count)
return E_INVALIDARG;
TRACE("ALSA does not support volume control\n");
@@ -3469,7 +3478,7 @@ static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
if(!levels)
return E_POINTER;
- if(count != This->fmt->nChannels)
+ if(count != This->channel_count)
return E_INVALIDARG;
EnterCriticalSection(&This->lock);
--
2.25.1
2
1