[PATCH 6/6] wineoss: Move create_stream and release_stream to the unixlib.

Huw Davies huw at codeweavers.com
Tue Apr 12 01:59:04 CDT 2022


Signed-off-by: Huw Davies <huw at codeweavers.com>
---
 dlls/wineoss.drv/mmdevdrv.c | 300 ++++--------------------------------
 dlls/wineoss.drv/oss.c      | 139 +++++++++++++++++
 dlls/wineoss.drv/unixlib.h  |  21 +++
 3 files changed, 191 insertions(+), 269 deletions(-)

diff --git a/dlls/wineoss.drv/mmdevdrv.c b/dlls/wineoss.drv/mmdevdrv.c
index 56b188424fb..2ea3c80f3ca 100644
--- a/dlls/wineoss.drv/mmdevdrv.c
+++ b/dlls/wineoss.drv/mmdevdrv.c
@@ -260,6 +260,16 @@ int WINAPI AUDDRV_GetPriority(void)
     return params.priority;
 }
 
+static HRESULT stream_release(struct oss_stream *stream)
+{
+    struct release_stream_params params;
+
+    params.stream = stream;
+    OSS_CALL(release_stream, &params);
+
+    return params.result;
+}
+
 static void oss_lock(struct oss_stream *stream)
 {
     pthread_mutex_lock(&stream->lock);
@@ -342,13 +352,6 @@ static void get_device_guid(EDataFlow flow, const char *device, GUID *guid)
         RegCloseKey(key);
 }
 
-static int open_device(const char *device, EDataFlow flow)
-{
-    int flags = ((flow == eRender) ? O_WRONLY : O_RDONLY) | O_NONBLOCK;
-
-    return open(device, flags, 0);
-}
-
 static void set_stream_volumes(ACImpl *This)
 {
     struct oss_stream *stream = This->stream;
@@ -524,7 +527,6 @@ static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface)
 static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
 {
     ACImpl *This = impl_from_IAudioClient3(iface);
-    struct oss_stream *stream = This->stream;
     ULONG ref;
 
     ref = InterlockedDecrement(&This->ref);
@@ -550,21 +552,8 @@ static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
             LeaveCriticalSection(&g_sessions_lock);
         }
         HeapFree(GetProcessHeap(), 0, This->vols);
-        if(stream){
-            SIZE_T size;
-            close(stream->fd);
-            if(stream->local_buffer){
-                size = 0;
-                NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, &size, MEM_RELEASE);
-            }
-            if(stream->tmp_buffer){
-                size = 0;
-                NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, &size, MEM_RELEASE);
-            }
-            CoTaskMemFree(stream->fmt);
-            pthread_mutex_destroy(&stream->lock);
-            HeapFree(GetProcessHeap(), 0, stream);
-        }
+        if(This->stream)
+            stream_release(This->stream);
         HeapFree(GetProcessHeap(), 0, This);
     }
     return ref;
@@ -604,177 +593,6 @@ static void dump_fmt(const WAVEFORMATEX *fmt)
     }
 }
 
-static DWORD get_channel_mask(unsigned int channels)
-{
-    switch(channels){
-    case 0:
-        return 0;
-    case 1:
-        return KSAUDIO_SPEAKER_MONO;
-    case 2:
-        return KSAUDIO_SPEAKER_STEREO;
-    case 3:
-        return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
-    case 4:
-        return KSAUDIO_SPEAKER_QUAD;    /* not _SURROUND */
-    case 5:
-        return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
-    case 6:
-        return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
-    case 7:
-        return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
-    case 8:
-        return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
-    }
-    FIXME("Unknown speaker configuration: %u\n", channels);
-    return 0;
-}
-
-static int get_oss_format(const WAVEFORMATEX *fmt)
-{
-    WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)fmt;
-
-    if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
-            (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
-             IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
-        switch(fmt->wBitsPerSample){
-        case 8:
-            return AFMT_U8;
-        case 16:
-            return AFMT_S16_LE;
-        case 24:
-            return AFMT_S24_LE;
-        case 32:
-            return AFMT_S32_LE;
-        }
-        return -1;
-    }
-
-#ifdef AFMT_FLOAT
-    if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
-            (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
-             IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
-        if(fmt->wBitsPerSample != 32)
-            return -1;
-
-        return AFMT_FLOAT;
-    }
-#endif
-
-    return -1;
-}
-
-static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
-{
-    WAVEFORMATEX *ret;
-    size_t size;
-
-    if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
-        size = sizeof(WAVEFORMATEXTENSIBLE);
-    else
-        size = sizeof(WAVEFORMATEX);
-
-    ret = CoTaskMemAlloc(size);
-    if(!ret)
-        return NULL;
-
-    memcpy(ret, fmt, size);
-
-    ret->cbSize = size - sizeof(WAVEFORMATEX);
-
-    return ret;
-}
-
-static HRESULT setup_oss_device(AUDCLNT_SHAREMODE mode, int fd,
-        const WAVEFORMATEX *fmt, WAVEFORMATEX **out)
-{
-    int tmp, oss_format;
-    double tenth;
-    HRESULT ret = S_OK;
-    WAVEFORMATEX *closest = NULL;
-
-    tmp = oss_format = get_oss_format(fmt);
-    if(oss_format < 0)
-        return AUDCLNT_E_UNSUPPORTED_FORMAT;
-    if(ioctl(fd, SNDCTL_DSP_SETFMT, &tmp) < 0){
-        WARN("SETFMT failed: %d (%s)\n", errno, strerror(errno));
-        return E_FAIL;
-    }
-    if(tmp != oss_format){
-        TRACE("Format unsupported by this OSS version: %x\n", oss_format);
-        return AUDCLNT_E_UNSUPPORTED_FORMAT;
-    }
-
-    if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
-            (fmt->nAvgBytesPerSec == 0 ||
-             fmt->nBlockAlign == 0 ||
-             ((WAVEFORMATEXTENSIBLE*)fmt)->Samples.wValidBitsPerSample > fmt->wBitsPerSample))
-        return E_INVALIDARG;
-
-    if(fmt->nChannels == 0)
-        return AUDCLNT_E_UNSUPPORTED_FORMAT;
-
-    closest = clone_format(fmt);
-    if(!closest)
-        return E_OUTOFMEMORY;
-
-    tmp = fmt->nSamplesPerSec;
-    if(ioctl(fd, SNDCTL_DSP_SPEED, &tmp) < 0){
-        WARN("SPEED failed: %d (%s)\n", errno, strerror(errno));
-        CoTaskMemFree(closest);
-        return E_FAIL;
-    }
-    tenth = fmt->nSamplesPerSec * 0.1;
-    if(tmp > fmt->nSamplesPerSec + tenth || tmp < fmt->nSamplesPerSec - tenth){
-        ret = S_FALSE;
-        closest->nSamplesPerSec = tmp;
-    }
-
-    tmp = fmt->nChannels;
-    if(ioctl(fd, SNDCTL_DSP_CHANNELS, &tmp) < 0){
-        WARN("CHANNELS failed: %d (%s)\n", errno, strerror(errno));
-        CoTaskMemFree(closest);
-        return E_FAIL;
-    }
-    if(tmp != fmt->nChannels){
-        ret = S_FALSE;
-        closest->nChannels = tmp;
-    }
-
-    if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
-        ((WAVEFORMATEXTENSIBLE*)closest)->dwChannelMask = get_channel_mask(closest->nChannels);
-
-    if(fmt->nBlockAlign != fmt->nChannels * fmt->wBitsPerSample / 8 ||
-            fmt->nAvgBytesPerSec != fmt->nBlockAlign * fmt->nSamplesPerSec ||
-            (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
-             ((WAVEFORMATEXTENSIBLE*)fmt)->Samples.wValidBitsPerSample < fmt->wBitsPerSample))
-        ret = S_FALSE;
-
-    if(mode == AUDCLNT_SHAREMODE_EXCLUSIVE &&
-            fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
-        if(((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask == 0 ||
-                ((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask & SPEAKER_RESERVED)
-            ret = S_FALSE;
-    }
-
-    if(ret == S_FALSE && !out)
-        ret = AUDCLNT_E_UNSUPPORTED_FORMAT;
-
-    if(ret == S_FALSE && out){
-        closest->nBlockAlign =
-            closest->nChannels * closest->wBitsPerSample / 8;
-        closest->nAvgBytesPerSec =
-            closest->nBlockAlign * closest->nSamplesPerSec;
-        if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
-            ((WAVEFORMATEXTENSIBLE*)closest)->Samples.wValidBitsPerSample = closest->wBitsPerSample;
-        *out = closest;
-    } else
-        CoTaskMemFree(closest);
-
-    TRACE("returning: %08x\n", ret);
-    return ret;
-}
-
 static void session_init_vols(AudioSession *session, UINT channels)
 {
     if(session->channel_count < channels){
@@ -860,11 +678,9 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
         const GUID *sessionguid)
 {
     ACImpl *This = impl_from_IAudioClient3(iface);
+    struct create_stream_params params;
     struct oss_stream *stream;
-    oss_audioinfo ai;
-    SIZE_T size;
-    int i;
-    HRESULT hr;
+    unsigned int i;
 
     TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
           wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
@@ -920,92 +736,38 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
         return AUDCLNT_E_ALREADY_INITIALIZED;
     }
 
-    stream = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This->stream));
-    if(!stream){
-        LeaveCriticalSection(&g_sessions_lock);
-        return E_OUTOFMEMORY;
-    }
-    stream->flow = This->dataflow;
-    pthread_mutex_init(&stream->lock, NULL);
-
-    stream->fd = open_device(This->devnode, This->dataflow);
-    if(stream->fd < 0){
-        WARN("Unable to open device %s: %d (%s)\n", This->devnode, errno, strerror(errno));
-        hr = AUDCLNT_E_DEVICE_INVALIDATED;
-        goto exit;
-    }
-
-    ai.dev = -1;
-    if(ioctl(stream->fd, SNDCTL_ENGINEINFO, &ai) < 0){
-        WARN("Unable to get audio info for device %s: %d (%s)\n", This->devnode, errno, strerror(errno));
-        hr = E_FAIL;
-        goto exit;
-    }
-
-    TRACE("OSS audioinfo:\n");
-    TRACE("devnode: %s\n", ai.devnode);
-    TRACE("name: %s\n", ai.name);
-    TRACE("busy: %x\n", ai.busy);
-    TRACE("caps: %x\n", ai.caps);
-    TRACE("iformats: %x\n", ai.iformats);
-    TRACE("oformats: %x\n", ai.oformats);
-    TRACE("enabled: %d\n", ai.enabled);
-    TRACE("min_rate: %d\n", ai.min_rate);
-    TRACE("max_rate: %d\n", ai.max_rate);
-    TRACE("min_channels: %d\n", ai.min_channels);
-    TRACE("max_channels: %d\n", ai.max_channels);
-
-    hr = setup_oss_device(mode, stream->fd, fmt, NULL);
-    if(FAILED(hr))
-        goto exit;
-
-    stream->fmt = clone_format(fmt);
-    if(!stream->fmt){
-        hr = E_OUTOFMEMORY;
-        goto exit;
-    }
-
-    stream->period_us = period / 10;
-    stream->period_frames = MulDiv(fmt->nSamplesPerSec, period, 10000000);
+    params.device = This->devnode;
+    params.flow = This->dataflow;
+    params.share = mode;
+    params.flags = flags;
+    params.duration = duration;
+    params.period = period;
+    params.fmt = fmt;
+    params.stream = &stream;
 
-    stream->bufsize_frames = MulDiv(duration, fmt->nSamplesPerSec, 10000000);
-    if(mode == AUDCLNT_SHAREMODE_EXCLUSIVE)
-        stream->bufsize_frames -= stream->bufsize_frames % stream->period_frames;
-    size = stream->bufsize_frames * fmt->nBlockAlign;
-    if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, 0, &size,
-                               MEM_COMMIT, PAGE_READWRITE)){
-        hr = E_OUTOFMEMORY;
-        goto exit;
+    OSS_CALL(create_stream, &params);
+    if(FAILED(params.result)){
+        LeaveCriticalSection(&g_sessions_lock);
+        return params.result;
     }
 
     This->channel_count = fmt->nChannels;
     This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float));
     if(!This->vols){
-        hr = E_OUTOFMEMORY;
+        params.result = E_OUTOFMEMORY;
         goto exit;
     }
     for(i = 0; i < This->channel_count; ++i)
         This->vols[i] = 1.f;
 
-    stream->share = mode;
-    stream->flags = flags;
-    stream->oss_bufsize_bytes = 0;
-
-    hr = get_audio_session(sessionguid, This->parent, This->channel_count,
+    params.result = get_audio_session(sessionguid, This->parent, This->channel_count,
             &This->session);
 
 exit:
-    if(FAILED(hr)){
+    if(FAILED(params.result)){
+        stream_release(stream);
         HeapFree(GetProcessHeap(), 0, This->vols);
         This->vols = NULL;
-        CoTaskMemFree(stream->fmt);
-        if(stream->fd >= 0) close(stream->fd);
-        if(stream->local_buffer){
-            size = 0;
-            NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, &size, MEM_RELEASE);
-        }
-        pthread_mutex_destroy(&stream->lock);
-        HeapFree(GetProcessHeap(), 0, stream);
     } else {
         list_add_tail(&This->session->clients, &This->entry);
         This->stream = stream;
@@ -1014,7 +776,7 @@ exit:
 
     LeaveCriticalSection(&g_sessions_lock);
 
-    return hr;
+    return params.result;
 }
 
 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface,
diff --git a/dlls/wineoss.drv/oss.c b/dlls/wineoss.drv/oss.c
index 389ec73ee10..628d0c5818a 100644
--- a/dlls/wineoss.drv/oss.c
+++ b/dlls/wineoss.drv/oss.c
@@ -31,6 +31,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <sys/soundcard.h>
+#include <pthread.h>
 
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
@@ -45,6 +46,30 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(oss);
 
+/* copied from kernelbase */
+static int muldiv( int a, int b, int c )
+{
+    LONGLONG ret;
+
+    if (!c) return -1;
+
+    /* We want to deal with a positive divisor to simplify the logic. */
+    if (c < 0)
+    {
+        a = -a;
+        c = -c;
+    }
+
+    /* If the result is positive, we "add" to round. else, we subtract to round. */
+    if ((a < 0 && b < 0) || (a >= 0 && b >= 0))
+        ret = (((LONGLONG)a * b) + (c / 2)) / c;
+    else
+        ret = (((LONGLONG)a * b) - (c / 2)) / c;
+
+    if (ret > 2147483647 || ret < -2147483647) return -1;
+    return ret;
+}
+
 static NTSTATUS test_connect(void *args)
 {
     struct test_connect_params *params = args;
@@ -466,6 +491,118 @@ static HRESULT setup_oss_device(AUDCLNT_SHAREMODE share, int fd,
     return ret;
 }
 
+static NTSTATUS create_stream(void *args)
+{
+    struct create_stream_params *params = args;
+    WAVEFORMATEXTENSIBLE *fmtex;
+    struct oss_stream *stream;
+    oss_audioinfo ai;
+    SIZE_T size;
+
+    stream = calloc(1, sizeof(*stream));
+    if(!stream){
+        params->result = E_OUTOFMEMORY;
+        return STATUS_SUCCESS;
+    }
+
+    stream->flow = params->flow;
+    pthread_mutex_init(&stream->lock, NULL);
+
+    stream->fd = open_device(params->device, params->flow);
+    if(stream->fd < 0){
+        WARN("Unable to open device %s: %d (%s)\n", params->device, errno, strerror(errno));
+        params->result = AUDCLNT_E_DEVICE_INVALIDATED;
+        goto exit;
+    }
+
+    ai.dev = -1;
+    if(ioctl(stream->fd, SNDCTL_ENGINEINFO, &ai) < 0){
+        WARN("Unable to get audio info for device %s: %d (%s)\n", params->device, errno, strerror(errno));
+        params->result = E_FAIL;
+        goto exit;
+    }
+
+    TRACE("OSS audioinfo:\n");
+    TRACE("devnode: %s\n", ai.devnode);
+    TRACE("name: %s\n", ai.name);
+    TRACE("busy: %x\n", ai.busy);
+    TRACE("caps: %x\n", ai.caps);
+    TRACE("iformats: %x\n", ai.iformats);
+    TRACE("oformats: %x\n", ai.oformats);
+    TRACE("enabled: %d\n", ai.enabled);
+    TRACE("min_rate: %d\n", ai.min_rate);
+    TRACE("max_rate: %d\n", ai.max_rate);
+    TRACE("min_channels: %d\n", ai.min_channels);
+    TRACE("max_channels: %d\n", ai.max_channels);
+
+    params->result = setup_oss_device(params->share, stream->fd, params->fmt, NULL);
+    if(FAILED(params->result))
+        goto exit;
+
+    fmtex = clone_format(params->fmt);
+    if(!fmtex){
+        params->result = E_OUTOFMEMORY;
+        goto exit;
+    }
+    stream->fmt = &fmtex->Format;
+
+    stream->period_us = params->period / 10;
+    stream->period_frames = muldiv(params->fmt->nSamplesPerSec, params->period, 10000000);
+
+    stream->bufsize_frames = muldiv(params->duration, params->fmt->nSamplesPerSec, 10000000);
+    if(params->share == AUDCLNT_SHAREMODE_EXCLUSIVE)
+        stream->bufsize_frames -= stream->bufsize_frames % stream->period_frames;
+    size = stream->bufsize_frames * params->fmt->nBlockAlign;
+    if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, 0, &size,
+                               MEM_COMMIT, PAGE_READWRITE)){
+        params->result = E_OUTOFMEMORY;
+        goto exit;
+    }
+
+    stream->share = params->share;
+    stream->flags = params->flags;
+    stream->oss_bufsize_bytes = 0;
+
+exit:
+    if(FAILED(params->result)){
+        if(stream->fd >= 0) close(stream->fd);
+        if(stream->local_buffer){
+            size = 0;
+            NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, &size, MEM_RELEASE);
+        }
+        pthread_mutex_destroy(&stream->lock);
+        free(stream->fmt);
+        free(stream);
+    }else{
+        *params->stream = stream;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+static NTSTATUS release_stream(void *args)
+{
+    struct release_stream_params *params = args;
+    struct oss_stream *stream = params->stream;
+    SIZE_T size;
+
+    close(stream->fd);
+    if(stream->local_buffer){
+        size = 0;
+        NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, &size, MEM_RELEASE);
+    }
+    if(stream->tmp_buffer){
+        size = 0;
+        NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, &size, MEM_RELEASE);
+    }
+    free(stream->fmt);
+    pthread_mutex_destroy(&stream->lock);
+    free(stream);
+
+    params->result = S_OK;
+    return STATUS_SUCCESS;
+}
+
 static NTSTATUS is_format_supported(void *args)
 {
     struct is_format_supported_params *params = args;
@@ -599,6 +736,8 @@ unixlib_entry_t __wine_unix_call_funcs[] =
 {
     test_connect,
     get_endpoint_ids,
+    create_stream,
+    release_stream,
     is_format_supported,
     get_mix_format,
 };
diff --git a/dlls/wineoss.drv/unixlib.h b/dlls/wineoss.drv/unixlib.h
index 8f82518b10e..c0a0b25c374 100644
--- a/dlls/wineoss.drv/unixlib.h
+++ b/dlls/wineoss.drv/unixlib.h
@@ -69,6 +69,25 @@ struct get_endpoint_ids_params
     unsigned int default_idx;
 };
 
+struct create_stream_params
+{
+    const char *device;
+    EDataFlow flow;
+    AUDCLNT_SHAREMODE share;
+    UINT flags;
+    REFERENCE_TIME duration;
+    REFERENCE_TIME period;
+    const WAVEFORMATEX *fmt;
+    HRESULT result;
+    struct oss_stream **stream;
+};
+
+struct release_stream_params
+{
+    struct oss_stream *stream;
+    HRESULT result;
+};
+
 struct is_format_supported_params
 {
     const char *device;
@@ -91,6 +110,8 @@ enum oss_funcs
 {
     oss_test_connect,
     oss_get_endpoint_ids,
+    oss_create_stream,
+    oss_release_stream,
     oss_is_format_supported,
     oss_get_mix_format,
 };
-- 
2.25.1




More information about the wine-devel mailing list