Andrew Eikum : winealsa.drv: Implement device enumeration.

Alexandre Julliard julliard at winehq.org
Wed May 25 11:28:15 CDT 2011


Module: wine
Branch: master
Commit: 934a64cb3804e458da37b0f490b82633010293f5
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=934a64cb3804e458da37b0f490b82633010293f5

Author: Andrew Eikum <aeikum at codeweavers.com>
Date:   Tue May 24 13:59:36 2011 -0500

winealsa.drv: Implement device enumeration.

---

 dlls/winealsa.drv/mmdevdrv.c |  177 ++++++++++++++++++++++++++++++++++++++----
 1 files changed, 162 insertions(+), 15 deletions(-)

diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c
index 854f7b9..20958bf 100644
--- a/dlls/winealsa.drv/mmdevdrv.c
+++ b/dlls/winealsa.drv/mmdevdrv.c
@@ -134,6 +134,7 @@ static CRITICAL_SECTION g_sessions_lock;
 static struct list g_sessions = LIST_INIT(g_sessions);
 
 static const WCHAR defaultW[] = {'d','e','f','a','u','l','t',0};
+static const char defname[] = "default";
 
 static const IAudioClientVtbl AudioClient_Vtbl;
 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
@@ -206,40 +207,186 @@ BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
     return TRUE;
 }
 
-HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, void ***keys,
+static HRESULT alsa_get_card_devices(EDataFlow flow, WCHAR **ids, char **keys,
+        UINT *num, snd_ctl_t *ctl, int card, const WCHAR *cardnameW)
+{
+    static const WCHAR dashW[] = {' ','-',' ',0};
+    int err, device;
+    snd_pcm_info_t *info;
+
+    info = HeapAlloc(GetProcessHeap(), 0, snd_pcm_info_sizeof());
+    if(!info)
+        return E_OUTOFMEMORY;
+
+    snd_pcm_info_set_subdevice(info, 0);
+    snd_pcm_info_set_stream(info,
+            flow == eRender ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE);
+
+    device = -1;
+    for(err = snd_ctl_pcm_next_device(ctl, &device); device != -1 && err >= 0;
+            err = snd_ctl_pcm_next_device(ctl, &device)){
+        const char *devname;
+
+        snd_pcm_info_set_device(info, device);
+
+        if((err = snd_ctl_pcm_info(ctl, info)) < 0){
+            if(err == -ENOENT)
+                /* This device doesn't have the right stream direction */
+                continue;
+
+            WARN("Failed to get info for card %d, device %d: %d (%s)\n",
+                    card, device, err, snd_strerror(err));
+            continue;
+        }
+
+        if(ids && keys){
+            DWORD len, cardlen;
+
+            devname = snd_pcm_info_get_name(info);
+            if(!devname){
+                WARN("Unable to get device name for card %d, device %d\n", card,
+                        device);
+                continue;
+            }
+
+            cardlen = lstrlenW(cardnameW);
+            len = MultiByteToWideChar(CP_UNIXCP, 0, devname, -1, NULL, 0);
+            len += lstrlenW(dashW);
+            len += cardlen;
+            ids[*num] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+            if(!ids[*num]){
+                HeapFree(GetProcessHeap(), 0, info);
+                return E_OUTOFMEMORY;
+            }
+            memcpy(ids[*num], cardnameW, cardlen * sizeof(WCHAR));
+            memcpy(ids[*num] + cardlen, dashW, lstrlenW(dashW) * sizeof(WCHAR));
+            cardlen += lstrlenW(dashW);
+            MultiByteToWideChar(CP_UNIXCP, 0, devname, -1, ids[*num] + cardlen,
+                    len - cardlen);
+
+            keys[*num] = HeapAlloc(GetProcessHeap(), 0, 32);
+            if(!keys[*num]){
+                HeapFree(GetProcessHeap(), 0, info);
+                HeapFree(GetProcessHeap(), 0, ids[*num]);
+                return E_OUTOFMEMORY;
+            }
+            sprintf(keys[*num], "hw:%d,%d", card, device);
+        }
+
+        ++(*num);
+    }
+
+    HeapFree(GetProcessHeap(), 0, info);
+
+    if(err != 0)
+        WARN("Got a failure during device enumeration on card %d: %d (%s)\n",
+                card, err, snd_strerror(err));
+
+    return S_OK;
+}
+
+static HRESULT alsa_enum_devices(EDataFlow flow, WCHAR **ids, char **keys,
+        UINT *num)
+{
+    int err, card;
+
+    card = -1;
+    *num = 0;
+    for(err = snd_card_next(&card); card != -1 && err >= 0;
+            err = snd_card_next(&card)){
+        char cardpath[64];
+        const char *cardname;
+        WCHAR *cardnameW;
+        snd_ctl_t *ctl;
+        DWORD len;
+
+        sprintf(cardpath, "hw:%u", card);
+
+        if((err = snd_ctl_open(&ctl, cardpath, 0)) < 0){
+            WARN("Unable to open ctl for ALSA device %s: %d (%s)\n", cardpath,
+                    err, snd_strerror(err));
+            continue;
+        }
+
+        if((err = snd_card_get_name(card, (char **)&cardname)) < 0){
+            WARN("Unable to get card name for ALSA device %s: %d (%s)\n",
+                    cardpath, err, snd_strerror(err));
+            /* FIXME: Should be localized */
+            cardname = "Unknown soundcard";
+        }
+
+        len = MultiByteToWideChar(CP_UNIXCP, 0, cardname, -1, NULL, 0);
+        cardnameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        if(!cardnameW){
+            snd_ctl_close(ctl);
+            return E_OUTOFMEMORY;
+        }
+        MultiByteToWideChar(CP_UNIXCP, 0, cardname, -1, cardnameW, len);
+
+        alsa_get_card_devices(flow, ids, keys, num, ctl, card, cardnameW);
+
+        HeapFree(GetProcessHeap(), 0, cardnameW);
+
+        snd_ctl_close(ctl);
+    }
+
+    if(err != 0)
+        WARN("Got a failure during card enumeration: %d (%s)\n",
+                err, snd_strerror(err));
+
+    return S_OK;
+}
+
+HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, char ***keys,
         UINT *num, UINT *def_index)
 {
-    TRACE("%d %p %p %p\n", flow, ids, num, def_index);
+    HRESULT hr;
 
-    *num = 1;
-    *def_index = 0;
+    TRACE("%d %p %p %p %p\n", flow, ids, keys, num, def_index);
+
+    hr = alsa_enum_devices(flow, NULL, NULL, num);
+    if(FAILED(hr))
+        return hr;
 
-    *ids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *));
-    if(!*ids)
+    *ids = HeapAlloc(GetProcessHeap(), 0, (*num + 1) * sizeof(WCHAR *));
+    *keys = HeapAlloc(GetProcessHeap(), 0, (*num + 1) * sizeof(char *));
+    if(!*ids || !*keys){
+        HeapFree(GetProcessHeap(), 0, *ids);
+        HeapFree(GetProcessHeap(), 0, *keys);
         return E_OUTOFMEMORY;
+    }
 
     (*ids)[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(defaultW));
-    if(!(*ids)[0]){
+    memcpy((*ids)[0], defaultW, sizeof(defaultW));
+    (*keys)[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(defname));
+    memcpy((*keys)[0], defname, sizeof(defname));
+    *def_index = 0;
+
+    hr = alsa_enum_devices(flow, (*ids) + 1, (*keys) + 1, num);
+    if(FAILED(hr)){
+        int i;
+        for(i = 0; i < *num; ++i){
+            HeapFree(GetProcessHeap(), 0, (*ids)[i]);
+            HeapFree(GetProcessHeap(), 0, (*keys)[i]);
+        }
         HeapFree(GetProcessHeap(), 0, *ids);
+        HeapFree(GetProcessHeap(), 0, *keys);
         return E_OUTOFMEMORY;
     }
 
-    lstrcpyW((*ids)[0], defaultW);
-
-    *keys = HeapAlloc(GetProcessHeap(), 0, sizeof(void *));
-    (*keys)[0] = NULL;
+    ++(*num); /* for default device */
 
     return S_OK;
 }
 
-HRESULT WINAPI AUDDRV_GetAudioEndpoint(void *key, IMMDevice *dev,
+HRESULT WINAPI AUDDRV_GetAudioEndpoint(const char *key, IMMDevice *dev,
         EDataFlow dataflow, IAudioClient **out)
 {
     ACImpl *This;
     int err;
     snd_pcm_stream_t stream;
 
-    TRACE("%p %p %d %p\n", key, dev, dataflow, out);
+    TRACE("\"%s\" %p %d %p\n", key, dev, dataflow, out);
 
     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
     if(!This)
@@ -262,10 +409,10 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(void *key, IMMDevice *dev,
     }
 
     This->dataflow = dataflow;
-    if((err = snd_pcm_open(&This->pcm_handle, "default", stream,
+    if((err = snd_pcm_open(&This->pcm_handle, key, stream,
                     SND_PCM_NONBLOCK)) < 0){
         HeapFree(GetProcessHeap(), 0, This);
-        WARN("Unable to open PCM \"default\": %d (%s)\n", err,
+        WARN("Unable to open PCM \"%s\": %d (%s)\n", key, err,
                 snd_strerror(err));
         return E_FAIL;
     }




More information about the wine-cvs mailing list