-- v2: mmdevapi: Implement IAudioClient3_GetCurrentSharedModeEnginePeriod. mmdevapi: Complete IAudioClient3_GetSharedModeEnginePeriod. mmdevapi: Complete IAudioClient3_InitializeSharedAudioStream. mmdevapi: Introduce helper stream_init(). mmdevapi: Return errors early in adjust_timing().
From: Davide Beatrici git@davidebeatrici.dev
--- dlls/mmdevapi/client.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/dlls/mmdevapi/client.c b/dlls/mmdevapi/client.c index ed635bcf98a..1058c639ff9 100644 --- a/dlls/mmdevapi/client.c +++ b/dlls/mmdevapi/client.c @@ -140,21 +140,21 @@ static HRESULT adjust_timing(struct audio_client *client, const WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE *)fmt; if (fmtex->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && (fmtex->dwChannelMask == 0 || fmtex->dwChannelMask & SPEAKER_RESERVED)) - hr = AUDCLNT_E_UNSUPPORTED_FORMAT; + return AUDCLNT_E_UNSUPPORTED_FORMAT; else { if (*period == 0) *period = def_period; if (*period < min_period || *period > 5000000) - hr = AUDCLNT_E_INVALID_DEVICE_PERIOD; + return AUDCLNT_E_INVALID_DEVICE_PERIOD; else if (*duration > 20000000) /* The smaller the period, the lower this limit. */ - hr = AUDCLNT_E_BUFFER_SIZE_ERROR; + return AUDCLNT_E_BUFFER_SIZE_ERROR; else if (flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) { if (*duration != *period) - hr = AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL; + return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
- hr = AUDCLNT_E_DEVICE_IN_USE; + return AUDCLNT_E_DEVICE_IN_USE; } else if (*duration < 8 * *period) *duration = 8 * *period; /* May grow above 2s. */ }
From: Davide Beatrici git@davidebeatrici.dev
--- dlls/mmdevapi/client.c | 183 +++++++++++++++++++++-------------------- 1 file changed, 96 insertions(+), 87 deletions(-)
diff --git a/dlls/mmdevapi/client.c b/dlls/mmdevapi/client.c index 1058c639ff9..7a141f03e19 100644 --- a/dlls/mmdevapi/client.c +++ b/dlls/mmdevapi/client.c @@ -355,6 +355,100 @@ skip: return wcsdup(name); }
+static HRESULT stream_init(struct audio_client *client, + const AUDCLNT_SHAREMODE mode, const DWORD flags, + REFERENCE_TIME duration, REFERENCE_TIME period, + const WAVEFORMATEX *fmt, const GUID *sessionguid) +{ + struct create_stream_params params; + UINT32 i, channel_count; + stream_handle stream; + WCHAR *name; + + if (!fmt) + return E_POINTER; + + dump_fmt(fmt); + + if (mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE) + return E_INVALIDARG; + + if (flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS | + AUDCLNT_STREAMFLAGS_LOOPBACK | + AUDCLNT_STREAMFLAGS_EVENTCALLBACK | + AUDCLNT_STREAMFLAGS_NOPERSIST | + AUDCLNT_STREAMFLAGS_RATEADJUST | + AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED | + AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE | + AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED | + AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY | + AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)) { + FIXME("Unknown flags: %08lx\n", flags); + return E_INVALIDARG; + } + + if (FAILED(params.result = adjust_timing(client, &duration, &period, mode, flags, fmt))) + return params.result; + + sessions_lock(); + + if (client->stream) { + sessions_unlock(); + return AUDCLNT_E_ALREADY_INITIALIZED; + } + + if (FAILED(params.result = main_loop_start())) { + sessions_unlock(); + return params.result; + } + + params.name = name = get_application_name(); + params.device = client->device_name; + params.flow = client->dataflow; + params.share = mode; + params.flags = flags; + params.duration = duration; + params.period = period; + params.fmt = fmt; + params.channel_count = &channel_count; + params.stream = &stream; + + wine_unix_call(create_stream, ¶ms); + + free(name); + + if (FAILED(params.result)) { + sessions_unlock(); + return params.result; + } + + if (!(client->vols = malloc(channel_count * sizeof(*client->vols)))) { + params.result = E_OUTOFMEMORY; + goto exit; + } + + for (i = 0; i < channel_count; i++) + client->vols[i] = 1.f; + + params.result = get_audio_session(sessionguid, client->parent, channel_count, &client->session); + +exit: + if (FAILED(params.result)) { + stream_release(stream, NULL); + free(client->vols); + client->vols = NULL; + } else { + list_add_tail(&client->session->clients, &client->entry); + client->stream = stream; + client->channel_count = channel_count; + set_stream_volumes(client); + } + + sessions_unlock(); + + return params.result; +} + static HRESULT WINAPI capture_QueryInterface(IAudioCaptureClient *iface, REFIID riid, void **ppv) { struct audio_client *This = impl_from_IAudioCaptureClient(iface); @@ -537,97 +631,12 @@ static HRESULT WINAPI client_Initialize(IAudioClient3 *iface, AUDCLNT_SHAREMODE const WAVEFORMATEX *fmt, const GUID *sessionguid) { struct audio_client *This = impl_from_IAudioClient3(iface); - struct create_stream_params params; - UINT32 i, channel_count; - stream_handle stream; - WCHAR *name;
TRACE("(%p)->(%x, %lx, %s, %s, %p, %s)\n", This, mode, flags, wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
- if (!fmt) - return E_POINTER; - - dump_fmt(fmt); - - if (mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE) - return E_INVALIDARG; - - if (flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS | - AUDCLNT_STREAMFLAGS_LOOPBACK | - AUDCLNT_STREAMFLAGS_EVENTCALLBACK | - AUDCLNT_STREAMFLAGS_NOPERSIST | - AUDCLNT_STREAMFLAGS_RATEADJUST | - AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED | - AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE | - AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED | - AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY | - AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)) { - FIXME("Unknown flags: %08lx\n", flags); - return E_INVALIDARG; - } - - if (FAILED(params.result = adjust_timing(This, &duration, &period, mode, flags, fmt))) - return params.result; - - sessions_lock(); - - if (This->stream) { - sessions_unlock(); - return AUDCLNT_E_ALREADY_INITIALIZED; - } - - if (FAILED(params.result = main_loop_start())) { - sessions_unlock(); - return params.result; - } - - params.name = name = get_application_name(); - params.device = This->device_name; - params.flow = This->dataflow; - params.share = mode; - params.flags = flags; - params.duration = duration; - params.period = period; - params.fmt = fmt; - params.channel_count = &channel_count; - params.stream = &stream; - - wine_unix_call(create_stream, ¶ms); - - free(name); - - if (FAILED(params.result)) { - sessions_unlock(); - return params.result; - } - - if (!(This->vols = malloc(channel_count * sizeof(*This->vols)))) { - params.result = E_OUTOFMEMORY; - goto exit; - } - - for (i = 0; i < channel_count; i++) - This->vols[i] = 1.f; - - params.result = get_audio_session(sessionguid, This->parent, channel_count, &This->session); - -exit: - if (FAILED(params.result)) { - stream_release(stream, NULL); - free(This->vols); - This->vols = NULL; - } else { - list_add_tail(&This->session->clients, &This->entry); - This->stream = stream; - This->channel_count = channel_count; - set_stream_volumes(This); - } - - sessions_unlock(); - - return params.result; + return stream_init(This, mode, flags, duration, period, fmt, sessionguid); }
static HRESULT WINAPI client_GetBufferSize(IAudioClient3 *iface, UINT32 *out) @@ -1025,7 +1034,7 @@ static HRESULT WINAPI client_InitializeSharedAudioStream(IAudioClient3 *iface, D return E_POINTER;
duration = period_frames * (REFERENCE_TIME)10000000 / format->nSamplesPerSec; - return client_Initialize(iface, AUDCLNT_SHAREMODE_SHARED, flags, duration, 0, format, session_guid); + return stream_init(This, AUDCLNT_SHAREMODE_SHARED, flags, duration, 0, format, session_guid); }
const IAudioClient3Vtbl AudioClient3_Vtbl =
From: Davide Beatrici git@davidebeatrici.dev
--- dlls/mmdevapi/client.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/dlls/mmdevapi/client.c b/dlls/mmdevapi/client.c index 7a141f03e19..1d6eefd5dbb 100644 --- a/dlls/mmdevapi/client.c +++ b/dlls/mmdevapi/client.c @@ -117,7 +117,7 @@ static HRESULT get_periods(struct audio_client *client, return params.result; }
-static HRESULT adjust_timing(struct audio_client *client, +static HRESULT adjust_timing(struct audio_client *client, const BOOLEAN force_def_period, REFERENCE_TIME *duration, REFERENCE_TIME *period, const AUDCLNT_SHAREMODE mode, const DWORD flags, const WAVEFORMATEX *fmt) @@ -133,7 +133,10 @@ static HRESULT adjust_timing(struct audio_client *client, TRACE("Device periods: %lu default and %lu minimum\n", (ULONG)def_period, (ULONG)min_period);
if (mode == AUDCLNT_SHAREMODE_SHARED) { - *period = def_period; + if (*period == 0 || force_def_period) + *period = def_period; + else if (*period < min_period) + return AUDCLNT_E_INVALID_DEVICE_PERIOD; if (*duration < 3 * *period) *duration = 3 * *period; } else { @@ -355,7 +358,7 @@ skip: return wcsdup(name); }
-static HRESULT stream_init(struct audio_client *client, +static HRESULT stream_init(struct audio_client *client, const BOOLEAN force_def_period, const AUDCLNT_SHAREMODE mode, const DWORD flags, REFERENCE_TIME duration, REFERENCE_TIME period, const WAVEFORMATEX *fmt, const GUID *sessionguid) @@ -387,7 +390,7 @@ static HRESULT stream_init(struct audio_client *client, return E_INVALIDARG; }
- if (FAILED(params.result = adjust_timing(client, &duration, &period, mode, flags, fmt))) + if (FAILED(params.result = adjust_timing(client, force_def_period, &duration, &period, mode, flags, fmt))) return params.result;
sessions_lock(); @@ -636,7 +639,7 @@ static HRESULT WINAPI client_Initialize(IAudioClient3 *iface, AUDCLNT_SHAREMODE wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
- return stream_init(This, mode, flags, duration, period, fmt, sessionguid); + return stream_init(This, TRUE, mode, flags, duration, period, fmt, sessionguid); }
static HRESULT WINAPI client_GetBufferSize(IAudioClient3 *iface, UINT32 *out) @@ -1027,14 +1030,16 @@ static HRESULT WINAPI client_InitializeSharedAudioStream(IAudioClient3 *iface, D const GUID *session_guid) { struct audio_client *This = impl_from_IAudioClient3(iface); - REFERENCE_TIME duration; - FIXME("(%p)->(0x%lx, %u, %p, %s) - partial stub\n", This, flags, period_frames, format, debugstr_guid(session_guid)); + REFERENCE_TIME period; + + TRACE("(%p)->(0x%lx, %u, %p, %s)\n", This, flags, period_frames, format, debugstr_guid(session_guid));
if (!format) return E_POINTER;
- duration = period_frames * (REFERENCE_TIME)10000000 / format->nSamplesPerSec; - return stream_init(This, AUDCLNT_SHAREMODE_SHARED, flags, duration, 0, format, session_guid); + period = period_frames * (REFERENCE_TIME)10000000 / format->nSamplesPerSec; + + return stream_init(This, FALSE, AUDCLNT_SHAREMODE_SHARED, flags, 0, period, format, session_guid); }
const IAudioClient3Vtbl AudioClient3_Vtbl =
From: Davide Beatrici git@davidebeatrici.dev
--- dlls/mmdevapi/client.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/dlls/mmdevapi/client.c b/dlls/mmdevapi/client.c index 1d6eefd5dbb..e0344aefa54 100644 --- a/dlls/mmdevapi/client.c +++ b/dlls/mmdevapi/client.c @@ -1002,17 +1002,23 @@ static HRESULT WINAPI client_GetSharedModeEnginePeriod(IAudioClient3 *iface, UINT32 *max_period_frames) { struct audio_client *This = impl_from_IAudioClient3(iface); - FIXME("(%p)->(%p, %p, %p, %p, %p) - partial stub\n", + REFERENCE_TIME def_period, min_period; + HRESULT hr; + + TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, format, default_period_frames, unit_period_frames, min_period_frames, max_period_frames);
- *default_period_frames = - *min_period_frames = - *max_period_frames = - format->nSamplesPerSec / 100; /* ~10ms */ - *unit_period_frames = 1; - return S_OK; + if (FAILED(hr = get_periods(This, &def_period, &min_period))) + return hr; + + *default_period_frames = def_period * format->nSamplesPerSec / (REFERENCE_TIME)10000000; + *min_period_frames = min_period * format->nSamplesPerSec / (REFERENCE_TIME)10000000; + *max_period_frames = *default_period_frames; + *unit_period_frames = 1; + + return hr; }
static HRESULT WINAPI client_GetCurrentSharedModeEnginePeriod(IAudioClient3 *iface,
From: Davide Beatrici git@davidebeatrici.dev
--- dlls/mmdevapi/client.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/dlls/mmdevapi/client.c b/dlls/mmdevapi/client.c index e0344aefa54..5be52cef803 100644 --- a/dlls/mmdevapi/client.c +++ b/dlls/mmdevapi/client.c @@ -1026,8 +1026,21 @@ static HRESULT WINAPI client_GetCurrentSharedModeEnginePeriod(IAudioClient3 *ifa UINT32 *cur_period_frames) { struct audio_client *This = impl_from_IAudioClient3(iface); - FIXME("(%p)->(%p, %p) - stub\n", This, cur_format, cur_period_frames); - return E_NOTIMPL; + UINT32 dummy; + HRESULT hr; + + TRACE("(%p)->(%p, %p)\n", This, cur_format, cur_period_frames); + + if (!cur_format || !cur_period_frames) + return E_POINTER; + + if (FAILED(hr = client_GetMixFormat(iface, cur_format))) + return hr; + + if (FAILED(hr = client_GetSharedModeEnginePeriod(iface, *cur_format, cur_period_frames, &dummy, &dummy, &dummy))) + return hr; + + return hr; }
static HRESULT WINAPI client_InitializeSharedAudioStream(IAudioClient3 *iface, DWORD flags,
On Thu Jun 20 18:08:31 2024 +0000, Davide Beatrici wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/5875/diffs?diff_id=118790&start_sha=35ec647293fdd397fcf76ca89269c4665241649e#99913733944fc35298a259705e992a42b21541f5_1060_1061)
As a bonus, there is no duplicate debug message (`InitializeSharedAudioStream()` + `Initialize()`) anymore.
Huw Davies (@huw) commented about dlls/mmdevapi/client.c:
- return E_NOTIMPL;
- UINT32 dummy;
- HRESULT hr;
- TRACE("(%p)->(%p, %p)\n", This, cur_format, cur_period_frames);
- if (!cur_format || !cur_period_frames)
return E_POINTER;
- if (FAILED(hr = client_GetMixFormat(iface, cur_format)))
return hr;
- if (FAILED(hr = client_GetSharedModeEnginePeriod(iface, *cur_format, cur_period_frames, &dummy, &dummy, &dummy)))
return hr;
- return hr;
Any reason not to return directly from `client_GetSharedModeEnginePeriod()`?
On Fri Jun 21 14:01:53 2024 +0000, Huw Davies wrote:
Any reason not to return directly from `client_GetSharedModeEnginePeriod()`?
No, my fault.