diff --git a/README.md b/README.md index d99cbac4..758142f5 100644 --- a/README.md +++ b/README.md @@ -37,11 +37,12 @@ Wine. All those differences are also documented on the Included bug fixes and improvements =================================== -**Bugfixes and features included in the next upcoming release [13]:** +**Bugfixes and features included in the next upcoming release [14]:** * Add stub for D3DXComputeTangentFrameEx ([Wine Bug #31984](https://bugs.winehq.org/show_bug.cgi?id=31984)) * Add stub for D3DXIntersect * Ensure X11 input events are handled even without explicit message loop ([Wine Bug #8854](https://bugs.winehq.org/show_bug.cgi?id=8854)) +* Expose PKEY_AudioEndpoint_PhysicalSpeakers device property in PulseAudio driver * Fix access violation when calling GetStringTypeW with NULL src. ([Wine Bug #37759](https://bugs.winehq.org/show_bug.cgi?id=37759)) * Fix handling of subdirectory in FtpFindFirstFile ([Wine Bug #16526](https://bugs.winehq.org/show_bug.cgi?id=16526)) * GetMonitorInfo returns the same name for all monitors ([Wine Bug #37709](https://bugs.winehq.org/show_bug.cgi?id=37709)) diff --git a/patches/Makefile b/patches/Makefile index ec4218e8..7ebe784c 100644 --- a/patches/Makefile +++ b/patches/Makefile @@ -2449,6 +2449,7 @@ winepulse-PulseAudio_Support.ok: $(call APPLY_FILE,winepulse-PulseAudio_Support/0030-winepulse-fix-segfault-in-pulse_rd_loop.patch) $(call APPLY_FILE,winepulse-PulseAudio_Support/0031-winepulse-implement-GetPropValue.patch) $(call APPLY_FILE,winepulse-PulseAudio_Support/0032-winepulse-fetch-actual-program-name-if-possible.patch) + $(call APPLY_FILE,winepulse-PulseAudio_Support/0033-winepulse-return-PKEY_AudioEndpoint_PhysicalSpeakers.patch) @( \ echo '+ { "Maarten Lankhorst", "winmm: Load winealsa if winepulse is found.", 1 },'; \ echo '+ { "Maarten Lankhorst", "winepulse: Add initial stub for pulseaudio support.", 1 },'; \ @@ -2482,6 +2483,7 @@ winepulse-PulseAudio_Support.ok: echo '+ { "Mark Harmstone", "winepulse: fix segfault in pulse_rd_loop.", 1 },'; \ echo '+ { "Mark Harmstone", "winepulse: implement GetPropValue.", 1 },'; \ echo '+ { "Mark Harmstone", "winepulse: fetch actual program name if possible.", 1 },'; \ + echo '+ { "Mark Harmstone", "winepulse: return PKEY_AudioEndpoint_PhysicalSpeakers device prop.", 1 },'; \ ) > winepulse-PulseAudio_Support.ok # Patchset winex11-CandidateWindowPos diff --git a/patches/winepulse-PulseAudio_Support/0033-winepulse-return-PKEY_AudioEndpoint_PhysicalSpeakers.patch b/patches/winepulse-PulseAudio_Support/0033-winepulse-return-PKEY_AudioEndpoint_PhysicalSpeakers.patch new file mode 100644 index 00000000..6e8bce25 --- /dev/null +++ b/patches/winepulse-PulseAudio_Support/0033-winepulse-return-PKEY_AudioEndpoint_PhysicalSpeakers.patch @@ -0,0 +1,155 @@ +From 044624c3318488cb5c540797bd03994e18a221fd Mon Sep 17 00:00:00 2001 +From: Mark Harmstone +Date: Wed, 10 Dec 2014 18:08:41 +0000 +Subject: winepulse: return PKEY_AudioEndpoint_PhysicalSpeakers device prop + +--- + dlls/winepulse.drv/mmdevdrv.c | 91 +++++++++++++++++++++++++++++++------------ + 1 file changed, 67 insertions(+), 24 deletions(-) + +diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c +index 445c242..c66ba54 100644 +--- a/dlls/winepulse.drv/mmdevdrv.c ++++ b/dlls/winepulse.drv/mmdevdrv.c +@@ -322,13 +322,44 @@ static const enum pa_channel_position pulse_pos_from_wfx[] = { + PA_CHANNEL_POSITION_TOP_REAR_RIGHT + }; + ++static DWORD pulse_channel_map_to_channel_mask(const pa_channel_map *map) { ++ int i; ++ DWORD mask = 0; ++ ++ for (i = 0; i < map->channels; ++i) ++ switch (map->map[i]) { ++ default: FIXME("Unhandled channel %s\n", pa_channel_position_to_string(map->map[i])); break; ++ case PA_CHANNEL_POSITION_FRONT_LEFT: mask |= SPEAKER_FRONT_LEFT; break; ++ case PA_CHANNEL_POSITION_MONO: ++ case PA_CHANNEL_POSITION_FRONT_CENTER: mask |= SPEAKER_FRONT_CENTER; break; ++ case PA_CHANNEL_POSITION_FRONT_RIGHT: mask |= SPEAKER_FRONT_RIGHT; break; ++ case PA_CHANNEL_POSITION_REAR_LEFT: mask |= SPEAKER_BACK_LEFT; break; ++ case PA_CHANNEL_POSITION_REAR_CENTER: mask |= SPEAKER_BACK_CENTER; break; ++ case PA_CHANNEL_POSITION_REAR_RIGHT: mask |= SPEAKER_BACK_RIGHT; break; ++ case PA_CHANNEL_POSITION_LFE: mask |= SPEAKER_LOW_FREQUENCY; break; ++ case PA_CHANNEL_POSITION_SIDE_LEFT: mask |= SPEAKER_SIDE_LEFT; break; ++ case PA_CHANNEL_POSITION_SIDE_RIGHT: mask |= SPEAKER_SIDE_RIGHT; break; ++ case PA_CHANNEL_POSITION_TOP_CENTER: mask |= SPEAKER_TOP_CENTER; break; ++ case PA_CHANNEL_POSITION_TOP_FRONT_LEFT: mask |= SPEAKER_TOP_FRONT_LEFT; break; ++ case PA_CHANNEL_POSITION_TOP_FRONT_CENTER: mask |= SPEAKER_TOP_FRONT_CENTER; break; ++ case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT: mask |= SPEAKER_TOP_FRONT_RIGHT; break; ++ case PA_CHANNEL_POSITION_TOP_REAR_LEFT: mask |= SPEAKER_TOP_BACK_LEFT; break; ++ case PA_CHANNEL_POSITION_TOP_REAR_CENTER: mask |= SPEAKER_TOP_BACK_CENTER; break; ++ case PA_CHANNEL_POSITION_TOP_REAR_RIGHT: mask |= SPEAKER_TOP_BACK_RIGHT; break; ++ case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER: mask |= SPEAKER_FRONT_LEFT_OF_CENTER; break; ++ case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER: mask |= SPEAKER_FRONT_RIGHT_OF_CENTER; break; ++ } ++ ++ return mask; ++} ++ + static void pulse_probe_settings(int render, WAVEFORMATEXTENSIBLE *fmt) { + WAVEFORMATEX *wfx = &fmt->Format; + pa_stream *stream; + pa_channel_map map; + pa_sample_spec ss; + pa_buffer_attr attr; +- int ret, i; ++ int ret; + unsigned int length = 0; + + pa_channel_map_init_auto(&map, 2, PA_CHANNEL_MAP_ALSA); +@@ -391,28 +422,7 @@ static void pulse_probe_settings(int render, WAVEFORMATEXTENSIBLE *fmt) { + else + fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + +- fmt->dwChannelMask = 0; +- for (i = 0; i < map.channels; ++i) +- switch (map.map[i]) { +- default: FIXME("Unhandled channel %s\n", pa_channel_position_to_string(map.map[i])); break; +- case PA_CHANNEL_POSITION_FRONT_LEFT: fmt->dwChannelMask |= SPEAKER_FRONT_LEFT; break; +- case PA_CHANNEL_POSITION_MONO: +- case PA_CHANNEL_POSITION_FRONT_CENTER: fmt->dwChannelMask |= SPEAKER_FRONT_CENTER; break; +- case PA_CHANNEL_POSITION_FRONT_RIGHT: fmt->dwChannelMask |= SPEAKER_FRONT_RIGHT; break; +- case PA_CHANNEL_POSITION_REAR_LEFT: fmt->dwChannelMask |= SPEAKER_BACK_LEFT; break; +- case PA_CHANNEL_POSITION_REAR_CENTER: fmt->dwChannelMask |= SPEAKER_BACK_CENTER; break; +- case PA_CHANNEL_POSITION_REAR_RIGHT: fmt->dwChannelMask |= SPEAKER_BACK_RIGHT; break; +- case PA_CHANNEL_POSITION_LFE: fmt->dwChannelMask |= SPEAKER_LOW_FREQUENCY; break; +- case PA_CHANNEL_POSITION_SIDE_LEFT: fmt->dwChannelMask |= SPEAKER_SIDE_LEFT; break; +- case PA_CHANNEL_POSITION_SIDE_RIGHT: fmt->dwChannelMask |= SPEAKER_SIDE_RIGHT; break; +- case PA_CHANNEL_POSITION_TOP_CENTER: fmt->dwChannelMask |= SPEAKER_TOP_CENTER; break; +- case PA_CHANNEL_POSITION_TOP_FRONT_LEFT: fmt->dwChannelMask |= SPEAKER_TOP_FRONT_LEFT; break; +- case PA_CHANNEL_POSITION_TOP_FRONT_CENTER: fmt->dwChannelMask |= SPEAKER_TOP_FRONT_CENTER; break; +- case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT: fmt->dwChannelMask |= SPEAKER_TOP_FRONT_RIGHT; break; +- case PA_CHANNEL_POSITION_TOP_REAR_LEFT: fmt->dwChannelMask |= SPEAKER_TOP_BACK_LEFT; break; +- case PA_CHANNEL_POSITION_TOP_REAR_CENTER: fmt->dwChannelMask |= SPEAKER_TOP_BACK_CENTER; break; +- case PA_CHANNEL_POSITION_TOP_REAR_RIGHT: fmt->dwChannelMask |= SPEAKER_TOP_BACK_RIGHT; break; +- } ++ fmt->dwChannelMask = pulse_channel_map_to_channel_mask(&map); + } + + typedef struct tagLANGANDCODEPAGE +@@ -3632,6 +3642,10 @@ static void pulse_prop_values_sink_info_cb(pa_context *c, const pa_sink_info *i, + st->pv->vt = VT_UI4; + st->pv->u.ulVal = Speakers; + st->hr = S_OK; ++ } else if (IsEqualPropertyKey(*st->prop, PKEY_AudioEndpoint_PhysicalSpeakers)) { ++ st->pv->vt = VT_UI4; ++ st->pv->u.ulVal = pulse_channel_map_to_channel_mask(&i->channel_map); ++ st->hr = S_OK; + } else + st->hr = E_NOTIMPL; + } +@@ -3658,6 +3672,16 @@ static void pulse_prop_values_source_info_cb(pa_context *c, const pa_source_info + pthread_cond_signal(&pulse_cond); + } + ++static void pulse_phys_speakers_cb(pa_context *c, const pa_sink_info *i, int eol, void *userdata) ++{ ++ PROPVARIANT *pv = userdata; ++ ++ if (i) ++ pv->u.ulVal |= pulse_channel_map_to_channel_mask(&i->channel_map); ++ ++ pthread_cond_signal(&pulse_cond); ++} ++ + HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARIANT *out) + { + struct pulse_prop_values_info_cb_data userdata; +@@ -3667,6 +3691,24 @@ HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARI + + TRACE("%s, (%s,%u), %p\n", wine_dbgstr_guid(guid), wine_dbgstr_guid(&prop->fmtid), prop->pid, out); + ++ if (IsEqualGUID(guid, &pulse_render_guid) && IsEqualPropertyKey(*prop, PKEY_AudioEndpoint_PhysicalSpeakers)) { ++ /* For default Pulseaudio render device, OR together all of the ++ * PKEY_AudioEndpoint_PhysicalSpeakers values of the sinks. */ ++ ++ out->vt = VT_UI4; ++ out->u.ulVal = 0; ++ ++ pthread_mutex_lock(&pulse_lock); ++ o = pa_context_get_sink_info_list(pulse_ctx, &pulse_phys_speakers_cb, out); ++ if (o) { ++ while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) ++ pthread_cond_wait(&pulse_cond, &pulse_lock); ++ pa_operation_unref(o); ++ } ++ pthread_mutex_unlock(&pulse_lock); ++ return o ? S_OK : E_FAIL; ++ } ++ + if (IsEqualGUID(guid, &pulse_render_guid) || IsEqualGUID(guid, &pulse_capture_guid)) + return E_NOTIMPL; + +@@ -3676,7 +3718,8 @@ HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARI + } + + if (!IsEqualPropertyKey(*prop, PKEY_AudioEndpoint_FormFactor) && +- !IsEqualPropertyKey(*prop, devicepath_key)) { ++ !IsEqualPropertyKey(*prop, devicepath_key) && ++ (flow == eCapture || !IsEqualPropertyKey(*prop, PKEY_AudioEndpoint_PhysicalSpeakers))) { + return E_NOTIMPL; + } + +-- +2.2.1 + diff --git a/patches/winepulse-PulseAudio_Support/definition b/patches/winepulse-PulseAudio_Support/definition index e0356258..f0552496 100644 --- a/patches/winepulse-PulseAudio_Support/definition +++ b/patches/winepulse-PulseAudio_Support/definition @@ -4,3 +4,4 @@ Fixes: [37042] Implement exclusive mode in PulseAudio backend Fixes: Fix possible segfault in pulse_rd_loop of PulseAudio backend Fixes: Add support for GetPropValue to PulseAudio backend Fixes: Use actual program name if available to describe PulseAudio streams +Fixes: Expose PKEY_AudioEndpoint_PhysicalSpeakers device property in PulseAudio driver