[PATCH 2/4] winealsa.drv: Add non-mmap support to capture

Maarten Lankhorst (none) mlankhorst at patser.
Mon Oct 5 02:10:53 CDT 2009


---
 dlls/winealsa.drv/dscapture.c |  137 ++++++++++++++++++++++++++++++-----------
 1 files changed, 100 insertions(+), 37 deletions(-)

diff --git a/dlls/winealsa.drv/dscapture.c b/dlls/winealsa.drv/dscapture.c
index ea1b202..f663b6c 100644
--- a/dlls/winealsa.drv/dscapture.c
+++ b/dlls/winealsa.drv/dscapture.c
@@ -92,6 +92,7 @@ struct IDsCaptureDriverBufferImpl
     CRITICAL_SECTION pcm_crst;
     LPBYTE mmap_buffer, presented_buffer;
     DWORD mmap_buflen_bytes, play_looping, mmap_ofs_bytes;
+    BOOL mmap;
 
     /* Note: snd_pcm_frames_to_bytes(This->pcm, mmap_buflen_frames) != mmap_buflen_bytes */
     /* The actual buffer may differ in size from the wanted buffer size */
@@ -342,30 +343,77 @@ static snd_pcm_uframes_t CommitAll(IDsCaptureDriverBufferImpl *This, DWORD force
     if (used < commitahead && (forced || This->play_looping))
     {
         snd_pcm_uframes_t done, putin = commitahead - used;
-        snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin);
-        CopyData(This, This->mmap_pos, putin);
-        done = snd_pcm_mmap_commit(This->pcm, This->mmap_pos, putin);
-        This->mmap_pos += done;
-        used += done;
-        putin = commitahead - used;
-
-        if (This->mmap_pos == This->mmap_buflen_frames && (snd_pcm_sframes_t)putin > 0 && This->play_looping)
+        if (This->mmap)
         {
             snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin);
-            This->mmap_ofs_bytes += snd_pcm_frames_to_bytes(This->pcm, This->mmap_buflen_frames);
-            This->mmap_ofs_bytes %= This->mmap_buflen_bytes;
             CopyData(This, This->mmap_pos, putin);
             done = snd_pcm_mmap_commit(This->pcm, This->mmap_pos, putin);
+
             This->mmap_pos += done;
             used += done;
+            putin = commitahead - used;
+
+            if (This->mmap_pos == This->mmap_buflen_frames && (snd_pcm_sframes_t)putin > 0 && This->play_looping)
+            {
+                This->mmap_ofs_bytes += snd_pcm_frames_to_bytes(This->pcm, This->mmap_buflen_frames);
+                This->mmap_ofs_bytes %= This->mmap_buflen_bytes;
+
+                snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin);
+                CopyData(This, This->mmap_pos, putin);
+                done = snd_pcm_mmap_commit(This->pcm, This->mmap_pos, putin);
+
+                This->mmap_pos += done;
+                used += done;
+            }
+        }
+        else
+        {
+            DWORD pos;
+            snd_pcm_sframes_t ret;
+
+            snd_pcm_uframes_t cap = snd_pcm_bytes_to_frames(This->pcm, This->mmap_buflen_bytes);
+            pos = realpos_to_fakepos(This, This->mmap_pos);
+            if (This->mmap_pos + putin > cap)
+                putin = cap - This->mmap_pos;
+            ret = snd_pcm_readi(This->pcm, This->presented_buffer + pos, putin);
+            if (ret == -EPIPE)
+            {
+                WARN("Underrun occurred\n");
+                snd_pcm_prepare(This->pcm);
+                ret = snd_pcm_readi(This->pcm, This->presented_buffer + pos, putin);
+                snd_pcm_start(This->pcm);
+            }
+            if (ret < 0)
+            {
+                WARN("Committing data: %ld / %s (%ld)\n", ret, snd_strerror(ret), putin);
+                ret = 0;
+            }
+            This->mmap_pos += ret;
+            used += ret;
+            /* At this point mmap_pos may be >= This->mmap_pos this is harmless
+             * realpos_to_fakepos handles it well, and below it is truncated
+             */
+
+            putin = commitahead - used;
+            if (putin > 0)
+            {
+                pos = realpos_to_fakepos(This, This->mmap_pos);
+                ret = snd_pcm_readi(This->pcm, This->presented_buffer + pos, putin);
+                if (ret > 0)
+                {
+                    This->mmap_pos += ret;
+                    used += ret;
+                }
+            }
         }
+
     }
 
-    if (This->mmap_pos == This->mmap_buflen_frames)
+    if (This->mmap_pos >= This->mmap_buflen_frames)
     {
         This->mmap_ofs_bytes += snd_pcm_frames_to_bytes(This->pcm, This->mmap_buflen_frames);
         This->mmap_ofs_bytes %= This->mmap_buflen_bytes;
-        This->mmap_pos = 0;
+        This->mmap_pos -= This->mmap_buflen_frames;
     }
 
     return used;
@@ -451,23 +499,30 @@ static int CreateMMAP(IDsCaptureDriverBufferImpl* pdbi)
     snd_pcm_sw_params_set_avail_min(pcm, sw_params, 0);
     err = snd_pcm_sw_params(pcm, sw_params);
 
-    avail = snd_pcm_avail_update(pcm);
-    if ((snd_pcm_sframes_t)avail < 0)
+    pdbi->mmap_ofs_bytes = 0;
+    if (!pdbi->mmap)
     {
-        ERR("No buffer is available: %s.\n", snd_strerror(avail));
-        return DSERR_GENERIC;
+        pdbi->mmap_buffer = NULL;
+
+        frames = snd_pcm_bytes_to_frames(pdbi->pcm, pdbi->mmap_buflen_bytes);
+        snd_pcm_format_set_silence(format, pdbi->presented_buffer, frames);
+        pdbi->mmap_pos = 0;
     }
-    err = snd_pcm_mmap_begin(pcm, &areas, &ofs, &avail);
-    if ( err < 0 )
+    else
     {
-        ERR("Can't map sound device for direct access: %s\n", snd_strerror(err));
-        return DSERR_GENERIC;
+        err = snd_pcm_mmap_begin(pcm, &areas, &ofs, &avail);
+        if ( err < 0 )
+        {
+            ERR("Can't map sound device for direct access: %s/%d\n", snd_strerror(err), err);
+            return DSERR_GENERIC;
+        }
+        snd_pcm_format_set_silence(format, areas->addr, pdbi->mmap_buflen_frames);
+        pdbi->mmap_pos = ofs + snd_pcm_mmap_commit(pcm, ofs, 0);
+        pdbi->mmap_buffer = areas->addr;
     }
-    err = snd_pcm_mmap_commit(pcm, ofs, 0);
-    pdbi->mmap_buffer = areas->addr;
 
     TRACE("created mmap buffer of %ld frames (%d bytes) at %p\n",
-        frames, pdbi->mmap_buflen_bytes, pdbi->mmap_buffer);
+        pdbi->mmap_buflen_frames, pdbi->mmap_buflen_bytes, pdbi->mmap_buffer);
 
     return DS_OK;
 }
@@ -591,6 +646,7 @@ static HRESULT WINAPI IDsCaptureDriverBufferImpl_SetFormat(PIDSCDRIVERBUFFER ifa
     snd_pcm_uframes_t buffer_size;
     DWORD rate = pwfx->nSamplesPerSec;
     int err=0;
+    BOOL mmap;
 
     TRACE("(%p, %p)\n", iface, pwfx);
 
@@ -632,9 +688,7 @@ static HRESULT WINAPI IDsCaptureDriverBufferImpl_SetFormat(PIDSCDRIVERBUFFER ifa
 
     /* Set some defaults */
     snd_pcm_hw_params_any(pcm, hw_params);
-    err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED);
-    if (err < 0) goto err;
-    
+
     err = snd_pcm_hw_params_set_channels(pcm, hw_params, pwfx->nChannels);
     if (err < 0) { WARN("Could not set channels to %d\n", pwfx->nChannels); goto err; }
 
@@ -657,9 +711,19 @@ static HRESULT WINAPI IDsCaptureDriverBufferImpl_SetFormat(PIDSCDRIVERBUFFER ifa
     snd_pcm_hw_params_set_buffer_size_near(pcm, hw_params, &buffer_size);
     buffer_size = 5000;
     snd_pcm_hw_params_set_period_time_near(pcm, hw_params, (unsigned int*)&buffer_size, NULL);
+
+    err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED);
+    if (err < 0)
+    {
+        err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
+        if (err < 0) { WARN("Could not set access\n"); goto err; }
+        mmap = 0;
+    }
+    else
+        mmap = 1;
+
     err = snd_pcm_hw_params(pcm, hw_params);
-    err = snd_pcm_sw_params(pcm, This->sw_params);
-    snd_pcm_prepare(pcm);
+    if (err < 0) { WARN("Could not set hw parameters\n"); goto err; }
 
     if (This->pcm)
     {
@@ -667,6 +731,7 @@ static HRESULT WINAPI IDsCaptureDriverBufferImpl_SetFormat(PIDSCDRIVERBUFFER ifa
         snd_pcm_close(This->pcm);
     }
     This->pcm = pcm;
+    This->mmap = mmap;
 
     snd_pcm_prepare(This->pcm);
     CreateMMAP(This);
@@ -708,8 +773,8 @@ static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetPosition(PIDSCDRIVERBUFFER i
 
     if (snd_pcm_state(This->pcm) != SND_PCM_STATE_RUNNING)
     {
-        hw_pptr = This->mmap_pos;
         CheckXRUN(This);
+        hw_pptr = This->mmap_pos;
     }
     else
     {
@@ -730,7 +795,7 @@ static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetPosition(PIDSCDRIVERBUFFER i
 
     LeaveCriticalSection(&This->pcm_crst);
 
-    TRACE("hw_pptr=0x%08x, hw_wptr=0x%08x playpos=%d, writepos=%d\n", (unsigned int)hw_pptr, (unsigned int)hw_wptr, lpdwCappos?*lpdwCappos:-1, lpdwReadpos?*lpdwReadpos:-1);
+    TRACE("hw_pptr=%u, hw_wptr=%u playpos=%u(%p), writepos=%u(%p)\n", (unsigned int)hw_pptr, (unsigned int)hw_wptr, realpos_to_fakepos(This, hw_pptr), lpdwCappos, realpos_to_fakepos(This, hw_wptr), lpdwReadpos);
     return DS_OK;
 }
 
@@ -893,7 +958,11 @@ static HRESULT WINAPI IDsCaptureDriverImpl_Open(PIDSCDRIVER iface)
     err = snd_pcm_hw_params_any(pcm, hw_params);
     if (err < 0) goto err;
     err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED);
-    if (err < 0) goto err;
+    if (err < 0)
+    {
+        err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
+        if (err < 0) goto err;
+    }
 
     TRACE("Success\n");
     snd_pcm_close(pcm);
@@ -1008,12 +1077,6 @@ DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv)
     IDsCaptureDriverImpl** idrv = (IDsCaptureDriverImpl**)drv;
     TRACE("(%d,%p)\n",wDevID,drv);
 
-    if (!(WInDev[wDevID].dwSupport & WAVECAPS_DIRECTSOUND))
-    {
-        WARN("Hardware accelerated capture not supported, falling back to wavein\n");
-        return MMSYSERR_NOTSUPPORTED;
-    }
-
     *idrv = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsCaptureDriverImpl));
     if (!*idrv)
         return MMSYSERR_NOMEM;
-- 
1.6.4.3


--------------070306080902020909070006--



More information about the wine-patches mailing list