From 5bbb7618f4ba0dc0f724e7edf58e32e8a0d27d48 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 15 Mar 2012 09:52:43 +0100 Subject: [PATCH] winepulse: Add format and period probing --- dlls/winepulse.drv/mmdevdrv.c | 128 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c index d187bdc6018..40db26d8344 100644 --- a/dlls/winepulse.drv/mmdevdrv.c +++ b/dlls/winepulse.drv/mmdevdrv.c @@ -70,6 +70,10 @@ static HANDLE pulse_thread; static pthread_mutex_t pulse_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t pulse_cond = PTHREAD_COND_INITIALIZER; +/* Mixer format + period times */ +static WAVEFORMATEXTENSIBLE pulse_fmt[2]; +static REFERENCE_TIME pulse_min_period[2], pulse_def_period[2]; + static DWORD pulse_stream_volume; const WCHAR pulse_keyW[] = {'S','o','f','t','w','a','r','e','\\', @@ -139,6 +143,121 @@ static DWORD CALLBACK pulse_mainloop_thread(void *tmp) { } static void pulse_contextcallback(pa_context *c, void *userdata); +static void pulse_stream_state(pa_stream *s, void *user); + +static const enum pa_channel_position pulse_pos_from_wfx[] = { + PA_CHANNEL_POSITION_FRONT_LEFT, + PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_FRONT_CENTER, + PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_REAR_LEFT, + PA_CHANNEL_POSITION_REAR_RIGHT, + PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, + PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, + PA_CHANNEL_POSITION_REAR_CENTER, + PA_CHANNEL_POSITION_SIDE_LEFT, + PA_CHANNEL_POSITION_SIDE_RIGHT, + PA_CHANNEL_POSITION_TOP_CENTER, + PA_CHANNEL_POSITION_TOP_FRONT_LEFT, + PA_CHANNEL_POSITION_TOP_FRONT_CENTER, + PA_CHANNEL_POSITION_TOP_FRONT_RIGHT, + PA_CHANNEL_POSITION_TOP_REAR_LEFT, + PA_CHANNEL_POSITION_TOP_REAR_CENTER, + PA_CHANNEL_POSITION_TOP_REAR_RIGHT +}; + +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; + unsigned int length = 0; + + pa_channel_map_init_auto(&map, 2, PA_CHANNEL_MAP_ALSA); + ss.rate = 48000; + ss.format = PA_SAMPLE_FLOAT32LE; + ss.channels = map.channels; + + attr.maxlength = -1; + attr.tlength = -1; + attr.minreq = attr.fragsize = pa_frame_size(&ss); + attr.prebuf = 0; + + stream = pa_stream_new(pulse_ctx, "format test stream", &ss, &map); + if (stream) + pa_stream_set_state_callback(stream, pulse_stream_state, NULL); + if (!stream) + ret = -1; + else if (render) + ret = pa_stream_connect_playback(stream, NULL, &attr, + PA_STREAM_START_CORKED|PA_STREAM_FIX_RATE|PA_STREAM_FIX_CHANNELS|PA_STREAM_EARLY_REQUESTS, NULL, NULL); + else + ret = pa_stream_connect_record(stream, NULL, &attr, PA_STREAM_START_CORKED|PA_STREAM_FIX_RATE|PA_STREAM_FIX_CHANNELS|PA_STREAM_EARLY_REQUESTS); + if (ret >= 0) { + while (pa_stream_get_state(stream) == PA_STREAM_CREATING) + pthread_cond_wait(&pulse_cond, &pulse_lock); + if (pa_stream_get_state(stream) == PA_STREAM_READY) { + ss = *pa_stream_get_sample_spec(stream); + map = *pa_stream_get_channel_map(stream); + if (render) + length = pa_stream_get_buffer_attr(stream)->minreq; + else + length = pa_stream_get_buffer_attr(stream)->fragsize; + pa_stream_disconnect(stream); + while (pa_stream_get_state(stream) == PA_STREAM_READY) + pthread_cond_wait(&pulse_cond, &pulse_lock); + } + } + if (stream) + pa_stream_unref(stream); + if (length) + pulse_def_period[!render] = pulse_min_period[!render] = pa_bytes_to_usec(10 * length, &ss); + else + pulse_min_period[!render] = MinimumPeriod; + if (pulse_def_period[!render] <= DefaultPeriod) + pulse_def_period[!render] = DefaultPeriod; + + wfx->wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wfx->cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); + wfx->nChannels = ss.channels; + wfx->wBitsPerSample = 8 * pa_sample_size_of_format(ss.format); + wfx->nSamplesPerSec = ss.rate; + wfx->nBlockAlign = pa_frame_size(&ss); + wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign; + if (ss.format != PA_SAMPLE_S24_32LE) + fmt->Samples.wValidBitsPerSample = wfx->wBitsPerSample; + else + fmt->Samples.wValidBitsPerSample = 24; + if (ss.format == PA_SAMPLE_FLOAT32LE) + fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + 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; + } +} static HRESULT pulse_connect(void) { @@ -199,6 +318,8 @@ static HRESULT pulse_connect(void) TRACE("Connected to server %s with protocol version: %i.\n", pa_context_get_server(pulse_ctx), pa_context_get_server_protocol_version(pulse_ctx)); + pulse_probe_settings(1, &pulse_fmt[0]); + pulse_probe_settings(0, &pulse_fmt[1]); return S_OK; fail: @@ -230,6 +351,13 @@ static void pulse_contextcallback(pa_context *c, void *userdata) { pthread_cond_signal(&pulse_cond); } +static void pulse_stream_state(pa_stream *s, void *user) +{ + pa_stream_state_t state = pa_stream_get_state(s); + TRACE("Stream state changed to %i\n", state); + pthread_cond_signal(&pulse_cond); +} + HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, void ***keys, UINT *num, UINT *def_index) { -- 2.11.4.GIT