Trace output with PulseAudio:
``` 0230:trace:mmdevapi:adjust_timing Requested duration 1000000 and period 0 0230:trace:mmdevapi:adjust_timing Device periods: 100000 default and 30000 minimum 0230:trace:mmdevapi:adjust_timing Adjusted duration 1000000 and period 100000 ```
-- v3: winepulse: Remove superfluous timing adjustment. wineoss: Remove superfluous timing adjustment. winecoreaudio: Remove superfluous timing adjustment. winealsa: Remove superfluous timing adjustment. mmdevapi: Adjust timing in AudioClient_Initialize. winealsa: Return minimum period in get_device_period if requested.
From: Davide Beatrici git@davidebeatrici.dev
--- dlls/winealsa.drv/alsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/winealsa.drv/alsa.c b/dlls/winealsa.drv/alsa.c index aa1ad4abe6c..3172e1ece81 100644 --- a/dlls/winealsa.drv/alsa.c +++ b/dlls/winealsa.drv/alsa.c @@ -2153,7 +2153,7 @@ static NTSTATUS alsa_get_device_period(void *args) if (params->def_period) *params->def_period = def_period; if (params->min_period) - *params->min_period = def_period; + *params->min_period = min_period;
params->result = S_OK;
From: Davide Beatrici git@davidebeatrici.dev
--- dlls/mmdevapi/client.c | 58 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+)
diff --git a/dlls/mmdevapi/client.c b/dlls/mmdevapi/client.c index e0c12b8e534..0b849e47e3d 100644 --- a/dlls/mmdevapi/client.c +++ b/dlls/mmdevapi/client.c @@ -99,6 +99,61 @@ static inline struct audio_client *impl_from_IAudioStreamVolume(IAudioStreamVolu return CONTAINING_RECORD(iface, struct audio_client, IAudioStreamVolume_iface); }
+static HRESULT adjust_timing(struct audio_client *This, + REFERENCE_TIME *duration, REFERENCE_TIME *period, + const AUDCLNT_SHAREMODE mode, const DWORD flags, + const WAVEFORMATEX *fmt) +{ + struct get_device_period_params params; + REFERENCE_TIME def_period, min_period; + + TRACE("Requested duration %lu and period %lu\n", (ULONG)*duration, (ULONG)*period); + + params.device = This->device_name; + params.flow = This->dataflow; + params.def_period = &def_period; + params.min_period = &min_period; + + wine_unix_call(get_device_period, ¶ms); + + if (FAILED(params.result)) + return params.result; + + TRACE("Device periods: %lu default and %lu minimum\n", (ULONG)def_period, (ULONG)min_period); + + if (mode == AUDCLNT_SHAREMODE_SHARED) { + *period = def_period; + if (*duration < 3 * *period) + *duration = 3 * *period; + } else { + const WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE *)fmt; + if (fmtex->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && + (fmtex->dwChannelMask == 0 || fmtex->dwChannelMask & SPEAKER_RESERVED)) + params.result = AUDCLNT_E_UNSUPPORTED_FORMAT; + else { + if (*period == 0) + *period = def_period; + if (*period < min_period || *period > 5000000) + params.result = AUDCLNT_E_INVALID_DEVICE_PERIOD; + else if (*duration > 20000000) /* The smaller the period, the lower this limit. */ + params.result = AUDCLNT_E_BUFFER_SIZE_ERROR; + else if (flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) { + if (*duration != *period) + params.result = AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL; + + FIXME("EXCLUSIVE mode with EVENTCALLBACK\n"); + + params.result = AUDCLNT_E_DEVICE_IN_USE; + } else if (*duration < 8 * *period) + *duration = 8 * *period; /* May grow above 2s. */ + } + } + + TRACE("Adjusted duration %lu and period %lu\n", (ULONG)*duration, (ULONG)*period); + + return params.result; +} + static void dump_fmt(const WAVEFORMATEX *fmt) { TRACE("wFormatTag: 0x%x (", fmt->wFormatTag); @@ -502,6 +557,9 @@ static HRESULT WINAPI client_Initialize(IAudioClient3 *iface, AUDCLNT_SHAREMODE return E_INVALIDARG; }
+ if (FAILED(params.result = adjust_timing(This, &duration, &period, mode, flags, fmt))) + return params.result; + sessions_lock();
if (This->stream) {
From: Davide Beatrici git@davidebeatrici.dev
--- dlls/winealsa.drv/alsa.c | 30 ------------------------------ 1 file changed, 30 deletions(-)
diff --git a/dlls/winealsa.drv/alsa.c b/dlls/winealsa.drv/alsa.c index 3172e1ece81..a24cb56d1d8 100644 --- a/dlls/winealsa.drv/alsa.c +++ b/dlls/winealsa.drv/alsa.c @@ -810,36 +810,6 @@ static NTSTATUS alsa_create_stream(void *args)
params->result = S_OK;
- if (params->share == AUDCLNT_SHAREMODE_SHARED) { - params->period = def_period; - if (params->duration < 3 * params->period) - params->duration = 3 * params->period; - } else { - if (fmtex->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && - (fmtex->dwChannelMask == 0 || fmtex->dwChannelMask & SPEAKER_RESERVED)) - params->result = AUDCLNT_E_UNSUPPORTED_FORMAT; - else { - if (!params->period) - params->period = def_period; - if (params->period < min_period || params->period > 5000000) - params->result = AUDCLNT_E_INVALID_DEVICE_PERIOD; - else if (params->duration > 20000000) /* The smaller the period, the lower this limit. */ - params->result = AUDCLNT_E_BUFFER_SIZE_ERROR; - else if (params->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) { - if (params->duration != params->period) - params->result = AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL; - - FIXME("EXCLUSIVE mode with EVENTCALLBACK\n"); - - params->result = AUDCLNT_E_DEVICE_IN_USE; - } else if (params->duration < 8 * params->period) - params->duration = 8 * params->period; /* May grow above 2s. */ - } - } - - if (FAILED(params->result)) - return STATUS_SUCCESS; - stream = calloc(1, sizeof(*stream)); if(!stream){ params->result = E_OUTOFMEMORY;
From: Davide Beatrici git@davidebeatrici.dev
--- dlls/winecoreaudio.drv/coreaudio.c | 31 ------------------------------ 1 file changed, 31 deletions(-)
diff --git a/dlls/winecoreaudio.drv/coreaudio.c b/dlls/winecoreaudio.drv/coreaudio.c index a79a0d16839..deb9df1b45a 100644 --- a/dlls/winecoreaudio.drv/coreaudio.c +++ b/dlls/winecoreaudio.drv/coreaudio.c @@ -725,37 +725,6 @@ static NTSTATUS unix_create_stream(void *args)
params->result = S_OK;
- if (params->share == AUDCLNT_SHAREMODE_SHARED) { - params->period = def_period; - if (params->duration < 3 * params->period) - params->duration = 3 * params->period; - } else { - const WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE *)params->fmt; - if (fmtex->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && - (fmtex->dwChannelMask == 0 || fmtex->dwChannelMask & SPEAKER_RESERVED)) - params->result = AUDCLNT_E_UNSUPPORTED_FORMAT; - else { - if (!params->period) - params->period = def_period; - if (params->period < min_period || params->period > 5000000) - params->result = AUDCLNT_E_INVALID_DEVICE_PERIOD; - else if (params->duration > 20000000) /* The smaller the period, the lower this limit. */ - params->result = AUDCLNT_E_BUFFER_SIZE_ERROR; - else if (params->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) { - if (params->duration != params->period) - params->result = AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL; - - FIXME("EXCLUSIVE mode with EVENTCALLBACK\n"); - - params->result = AUDCLNT_E_DEVICE_IN_USE; - } else if (params->duration < 8 * params->period) - params->duration = 8 * params->period; /* May grow above 2s. */ - } - } - - if (FAILED(params->result)) - return STATUS_SUCCESS; - if (!(stream = calloc(1, sizeof(*stream)))) { params->result = E_OUTOFMEMORY; return STATUS_SUCCESS;
From: Davide Beatrici git@davidebeatrici.dev
--- dlls/wineoss.drv/oss.c | 30 ------------------------------ 1 file changed, 30 deletions(-)
diff --git a/dlls/wineoss.drv/oss.c b/dlls/wineoss.drv/oss.c index 89e626f39d6..819e876606c 100644 --- a/dlls/wineoss.drv/oss.c +++ b/dlls/wineoss.drv/oss.c @@ -576,36 +576,6 @@ static NTSTATUS oss_create_stream(void *args)
params->result = S_OK;
- if (params->share == AUDCLNT_SHAREMODE_SHARED) { - params->period = def_period; - if (params->duration < 3 * params->period) - params->duration = 3 * params->period; - } else { - if (fmtex->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && - (fmtex->dwChannelMask == 0 || fmtex->dwChannelMask & SPEAKER_RESERVED)) - params->result = AUDCLNT_E_UNSUPPORTED_FORMAT; - else { - if (!params->period) - params->period = def_period; - if (params->period < min_period || params->period > 5000000) - params->result = AUDCLNT_E_INVALID_DEVICE_PERIOD; - else if (params->duration > 20000000) /* The smaller the period, the lower this limit. */ - params->result = AUDCLNT_E_BUFFER_SIZE_ERROR; - else if (params->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) { - if (params->duration != params->period) - params->result = AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL; - - FIXME("EXCLUSIVE mode with EVENTCALLBACK\n"); - - params->result = AUDCLNT_E_DEVICE_IN_USE; - } else if (params->duration < 8 * params->period) - params->duration = 8 * params->period; /* May grow above 2s. */ - } - } - - if (FAILED(params->result)) - return STATUS_SUCCESS; - stream = calloc(1, sizeof(*stream)); if(!stream){ params->result = E_OUTOFMEMORY;
From: Davide Beatrici git@davidebeatrici.dev
Please note that exclusive mode is not supported in this driver. --- dlls/winepulse.drv/pulse.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-)
diff --git a/dlls/winepulse.drv/pulse.c b/dlls/winepulse.drv/pulse.c index 62658fc98e6..dd8d0b4441d 100644 --- a/dlls/winepulse.drv/pulse.c +++ b/dlls/winepulse.drv/pulse.c @@ -1116,7 +1116,6 @@ static HRESULT get_device_period_helper(EDataFlow flow, const char *pulse_name, static NTSTATUS pulse_create_stream(void *args) { struct create_stream_params *params = args; - REFERENCE_TIME period, duration = params->duration; struct pulse_stream *stream; unsigned int i, bufsize_bytes; HRESULT hr; @@ -1156,21 +1155,15 @@ static NTSTATUS pulse_create_stream(void *args) if (FAILED(hr)) goto exit;
- period = 0; - hr = get_device_period_helper(params->flow, params->device, &period, NULL); - if (FAILED(hr)) - goto exit; - - if (duration < 3 * period) - duration = 3 * period; - - stream->def_period = period; + stream->def_period = params->period;
- stream->period_bytes = pa_frame_size(&stream->ss) * muldiv(period, stream->ss.rate, 10000000); + stream->period_bytes = pa_frame_size(&stream->ss) * muldiv(params->period, + stream->ss.rate, + 10000000);
- stream->bufsize_frames = ceil((duration / 10000000.) * params->fmt->nSamplesPerSec); + stream->bufsize_frames = ceil((params->duration / 10000000.) * params->fmt->nSamplesPerSec); bufsize_bytes = stream->bufsize_frames * pa_frame_size(&stream->ss); - stream->mmdev_period_usec = period / 10; + stream->mmdev_period_usec = params->period / 10;
stream->share = params->share; stream->flags = params->flags;
On Wed May 29 19:57:22 2024 +0000, Huw Davies wrote:
Let's add a separate commit, at the beginning of this series, to change alsa's `get_device_period()` to return `min_period`.
Done.
This merge request was approved by Huw Davies.