[PATCH 2/5] winepulse: Add format and period probing

Andrew Eikum aeikum at codeweavers.com
Fri Oct 16 11:05:46 CDT 2015


From: Maarten Lankhorst <m.b.lankhorst at gmail.com>

Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>
---
 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 173a264..338ed6a 100644
--- a/dlls/winepulse.drv/mmdevdrv.c
+++ b/dlls/winepulse.drv/mmdevdrv.c
@@ -79,6 +79,10 @@ static HANDLE pulse_thread;
 static pthread_mutex_t pulse_lock;
 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 GUID pulse_render_guid =
 { 0xfd47d9cc, 0x4218, 0x4135, { 0x9c, 0xe2, 0x0c, 0x19, 0x5c, 0x87, 0x40, 0x5b } };
 static GUID pulse_capture_guid =
@@ -151,6 +155,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)
 {
@@ -211,6 +330,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:
@@ -242,6 +363,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, const WCHAR ***ids, GUID **keys,
         UINT *num, UINT *def_index)
 {
-- 
2.6.1





More information about the wine-patches mailing list