[PATCH 2/3] winecoreaudio.drv: Rewrite capture mode

Andrew Eikum aeikum at codeweavers.com
Wed Aug 21 10:16:05 CDT 2013


---
 dlls/winecoreaudio.drv/mmdevdrv.c | 202 ++++++++++++++++++++------------------
 1 file changed, 104 insertions(+), 98 deletions(-)

diff --git a/dlls/winecoreaudio.drv/mmdevdrv.c b/dlls/winecoreaudio.drv/mmdevdrv.c
index ab3c2c9..bfc6eb8 100644
--- a/dlls/winecoreaudio.drv/mmdevdrv.c
+++ b/dlls/winecoreaudio.drv/mmdevdrv.c
@@ -61,8 +61,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(coreaudio);
 
 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
 
-#define CAPTURE_BUFFERS 5
-
 static const REFERENCE_TIME DefaultPeriod = 200000;
 static const REFERENCE_TIME MinimumPeriod = 100000;
 
@@ -134,11 +132,12 @@ struct ACImpl {
     AudioQueueRef aqueue;
     AudioObjectPropertyScope scope;
     HANDLE timer;
-    UINT32 period_ms, bufsize_frames, inbuf_frames;
+    UINT32 period_ms, bufsize_frames, inbuf_frames, read_offs_bytes, period_frames;
     UINT64 last_time, written_frames;
     AudioQueueBufferRef public_buffer;
     UINT32 getbuf_last;
     int playing;
+    BYTE *tmp_buffer, *capture_buf;
 
     Float64 highest_sampletime, next_sampletime;
 
@@ -199,7 +198,6 @@ static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
 static struct list g_sessions = LIST_INIT(g_sessions);
 
-static HRESULT AudioCaptureClient_GetNextPacket(ACImpl *This, UINT32 *frames);
 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
 static HRESULT ca_setvol(ACImpl *This, UINT32 index);
 
@@ -739,14 +737,53 @@ static UINT64 get_current_aqbuffer_position(ACImpl *This, int mode)
 static void avail_update(ACImpl *This)
 {
     AQBuffer *buf, *next;
+    OSStatus sc;
 
-    LIST_FOR_EACH_ENTRY_SAFE(buf, next, &This->queued_buffers, AQBuffer, entry){
-        if(buf->used)
-            break;
-        if(This->dataflow == eCapture)
-            This->inbuf_frames += buf->buf->mAudioDataByteSize / This->fmt->nBlockAlign;
-        list_remove(&buf->entry);
-        list_add_tail(&This->avail_buffers, &buf->entry);
+    if(This->dataflow == eCapture){
+        DWORD bufsize_bytes = This->bufsize_frames * This->fmt->nBlockAlign;
+        DWORD inbuf_bytes = This->inbuf_frames * This->fmt->nBlockAlign;
+
+        LIST_FOR_EACH_ENTRY_SAFE(buf, next, &This->queued_buffers, AQBuffer, entry){
+            DWORD buffer_bytes = buf->buf->mAudioDataByteSize, to_copy_bytes;
+
+            if(buf->used)
+                break;
+
+            to_copy_bytes = bufsize_bytes - (This->read_offs_bytes + inbuf_bytes) % bufsize_bytes;
+
+            if(buffer_bytes <= to_copy_bytes){
+                memcpy(This->capture_buf + (This->read_offs_bytes + inbuf_bytes) % bufsize_bytes,
+                        buf->buf->mAudioData, buffer_bytes);
+            }else{
+                memcpy(This->capture_buf + (This->read_offs_bytes + inbuf_bytes) % bufsize_bytes,
+                        buf->buf->mAudioData, to_copy_bytes);
+                memcpy(This->capture_buf, ((char *)buf->buf->mAudioData) + to_copy_bytes,
+                        buffer_bytes - to_copy_bytes);
+            }
+
+            if(inbuf_bytes + buffer_bytes > bufsize_bytes){
+                This->read_offs_bytes += inbuf_bytes + buffer_bytes;
+                This->read_offs_bytes %= bufsize_bytes;
+                inbuf_bytes = bufsize_bytes;
+            }else
+                inbuf_bytes += buffer_bytes;
+
+            buf->used = TRUE;
+            list_remove(&buf->entry);
+            list_add_tail(&This->queued_buffers, &buf->entry);
+            sc = AudioQueueEnqueueBuffer(This->aqueue, buf->buf, 0, NULL);
+            if(sc != noErr)
+                WARN("EnqueueBuffer gave: %lx\n", sc);
+        }
+
+        This->inbuf_frames = inbuf_bytes / This->fmt->nBlockAlign;
+    }else{
+        LIST_FOR_EACH_ENTRY_SAFE(buf, next, &This->queued_buffers, AQBuffer, entry){
+            if(buf->used)
+                break;
+            list_remove(&buf->entry);
+            list_add_tail(&This->avail_buffers, &buf->entry);
+        }
     }
 }
 
@@ -819,6 +856,8 @@ static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
             LeaveCriticalSection(&g_sessions_lock);
         }
         HeapFree(GetProcessHeap(), 0, This->vols);
+        HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
+        HeapFree(GetProcessHeap(), 0, This->capture_buf);
         CoTaskMemFree(This->fmt);
         IMMDevice_Release(This->parent);
         IUnknown_Release(This->pUnkFTMarshal);
@@ -1191,18 +1230,21 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
     }
 
     This->period_ms = period / 10000;
+    This->period_frames = MulDiv(period, This->fmt->nSamplesPerSec, 10000000);
 
     This->bufsize_frames = MulDiv(duration, fmt->nSamplesPerSec, 10000000);
 
     if(This->dataflow == eCapture){
-        int i;
-        UInt32 bsize = ceil((This->bufsize_frames / (double)CAPTURE_BUFFERS) *
-                This->fmt->nBlockAlign);
-        for(i = 0; i < CAPTURE_BUFFERS; ++i){
+        int i, nbuffs = (This->bufsize_frames / This->period_frames) + 1;
+
+        This->capture_buf = HeapAlloc(GetProcessHeap(), 0, This->bufsize_frames * This->fmt->nBlockAlign);
+
+        for(i = 0; i < nbuffs; ++i){
             AQBuffer *buf;
 
             buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
             if(!buf){
+                HeapFree(GetProcessHeap(), 0, This->capture_buf);
                 AudioQueueDispose(This->aqueue, 1);
                 This->aqueue = NULL;
                 CoTaskMemFree(This->fmt);
@@ -1211,8 +1253,9 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
                 return E_OUTOFMEMORY;
             }
 
-            sc = AudioQueueAllocateBuffer(This->aqueue, bsize, &buf->buf);
+            sc = AudioQueueAllocateBuffer(This->aqueue, This->period_frames * This->fmt->nBlockAlign, &buf->buf);
             if(sc != noErr){
+                HeapFree(GetProcessHeap(), 0, This->capture_buf);
                 AudioQueueDispose(This->aqueue, 1);
                 This->aqueue = NULL;
                 CoTaskMemFree(This->fmt);
@@ -1235,6 +1278,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
 
     This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
     if(!This->vols){
+        HeapFree(GetProcessHeap(), 0, This->capture_buf);
         AudioQueueDispose(This->aqueue, 1);
         This->aqueue = NULL;
         CoTaskMemFree(This->fmt);
@@ -1259,6 +1303,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
         This->aqueue = NULL;
         CoTaskMemFree(This->fmt);
         This->fmt = NULL;
+        HeapFree(GetProcessHeap(), 0, This->capture_buf);
         HeapFree(GetProcessHeap(), 0, This->vols);
         This->vols = NULL;
         OSSpinLockUnlock(&This->lock);
@@ -1417,8 +1462,11 @@ static HRESULT AudioClient_GetCurrentPadding_nolock(ACImpl *This,
         UINT64 bufpos;
         bufpos = get_current_aqbuffer_position(This, BUFPOS_RELATIVE);
         *numpad = This->inbuf_frames - bufpos;
-    }else
+    }else{
         *numpad = This->inbuf_frames;
+        if(*numpad < This->period_frames)
+            *numpad = 0;
+    }
 
     return S_OK;
 }
@@ -1663,10 +1711,8 @@ static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
             return E_OUTOFMEMORY;
         }
 
-    if(This->dataflow == eCapture){
-        UINT32 frames; /* enqueue packets */
-        AudioCaptureClient_GetNextPacket(This, &frames);
-    }
+    /* enqueue buffers */
+    avail_update(This);
 
     This->playing = StateInTransition;
 
@@ -1756,7 +1802,6 @@ static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
     ACImpl *This = impl_from_IAudioClient(iface);
     OSStatus sc;
     QueuedBufInfo *bufinfo, *bufinfo2;
-    AQBuffer *buf;
 
     TRACE("(%p)\n", This);
 
@@ -1792,14 +1837,9 @@ static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
         return osstatus_to_hresult(sc);
     }
 
-    /* AQReset is synchronous */
-    list_move_tail(&This->avail_buffers, &This->queued_buffers);
-
     if(This->dataflow == eRender){
         This->written_frames = 0;
     }else{
-        LIST_FOR_EACH_ENTRY(buf, &This->avail_buffers, AQBuffer, entry)
-            buf->buf->mAudioDataByteSize = 0;
         This->written_frames += This->inbuf_frames;
     }
     This->inbuf_frames = 0;
@@ -2205,49 +2245,12 @@ static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
     return IAudioClient_Release(&This->IAudioClient_iface);
 }
 
-static HRESULT AudioCaptureClient_GetNextPacket(ACImpl *This, UINT32 *frames)
-{
-    AQBuffer *buf;
-    OSStatus sc;
-
-    avail_update(This); /* once, not inside loop */
-
-    for(;;){
-        if(!This->public_buffer){
-            struct list *head = list_head(&This->avail_buffers);
-
-            if(!head){
-                *frames = 0;
-                return S_OK;
-            }
-            buf = LIST_ENTRY(head, AQBuffer, entry);
-            This->public_buffer = buf->buf;
-            list_remove(&buf->entry);
-        }else
-            buf = This->public_buffer->mUserData;
-        *frames = This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
-        if(*frames)
-            return S_OK;
-
-        WARN("empty packet\n");
-        buf->used = TRUE;
-        sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer, 0, NULL);
-        if(sc != noErr){
-            ERR("Unable to enqueue buffer: %lx\n", sc);
-            /* Release will free This->public_buffer */
-            return AUDCLNT_E_DEVICE_INVALIDATED;
-        }else
-            list_add_tail(&This->queued_buffers, &buf->entry);
-        This->public_buffer = NULL;
-    }
-}
-
 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
         BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
         UINT64 *qpcpos)
 {
     ACImpl *This = impl_from_IAudioCaptureClient(iface);
-    HRESULT hr;
+    DWORD chunk_bytes;
 
     TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
             devpos, qpcpos);
@@ -2262,36 +2265,46 @@ static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
         return AUDCLNT_E_OUT_OF_ORDER;
     }
 
-    hr = AudioCaptureClient_GetNextPacket(This, frames);
-    if(FAILED(hr)){
+    avail_update(This);
+
+    if(This->inbuf_frames < This->period_frames){
+        *frames = 0;
         OSSpinLockUnlock(&This->lock);
-        return hr;
+        return AUDCLNT_S_BUFFER_EMPTY;
     }
 
-    if((This->getbuf_last = *frames)){
-        *flags = 0;
-        *data = This->public_buffer->mAudioData;
+    *flags = 0;
 
-        if(devpos)
-            *devpos = This->written_frames;
-        if(qpcpos){ /* fixme: qpc of recording time */
-            LARGE_INTEGER stamp, freq;
-            QueryPerformanceCounter(&stamp);
-            QueryPerformanceFrequency(&freq);
-            *qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
-        }
+    chunk_bytes = This->bufsize_frames * This->fmt->nBlockAlign - This->read_offs_bytes;
+    if(chunk_bytes < This->period_frames * This->fmt->nBlockAlign){
+        if(!This->tmp_buffer)
+            This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, This->period_frames * This->fmt->nBlockAlign);
+        *data = This->tmp_buffer;
+        memcpy(*data, This->capture_buf + This->read_offs_bytes, chunk_bytes);
+        memcpy((*data) + chunk_bytes, This->capture_buf, This->period_frames * This->fmt->nBlockAlign - chunk_bytes);
+    }else
+        *data = This->capture_buf + This->read_offs_bytes;
+
+    This->getbuf_last = *frames = This->period_frames;
+
+    if(devpos)
+        *devpos = This->written_frames;
+    if(qpcpos){ /* fixme: qpc of recording time */
+        LARGE_INTEGER stamp, freq;
+        QueryPerformanceCounter(&stamp);
+        QueryPerformanceFrequency(&freq);
+        *qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
     }
+
     OSSpinLockUnlock(&This->lock);
 
-    return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
+    return S_OK;
 }
 
 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
         IAudioCaptureClient *iface, UINT32 done)
 {
     ACImpl *This = impl_from_IAudioCaptureClient(iface);
-    AQBuffer *buf;
-    OSStatus sc;
 
     TRACE("(%p)->(%u)\n", This, done);
 
@@ -2315,21 +2328,10 @@ static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
 
     This->written_frames += done;
     This->inbuf_frames -= done;
+    This->read_offs_bytes += done * This->fmt->nBlockAlign;
+    This->read_offs_bytes %= This->bufsize_frames * This->fmt->nBlockAlign;
     This->getbuf_last = 0;
 
-    buf = This->public_buffer->mUserData;
-    buf->used = TRUE;
-    sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer, 0, NULL);
-    if(sc != noErr){
-        OSSpinLockUnlock(&This->lock);
-        /* fixme: can't zero public_buffer or we lose memory, but then
-         * GetBuffer will see that packet again and again. */
-        ERR("Unable to enqueue buffer: %lx\n", sc);
-        return AUDCLNT_E_DEVICE_INVALIDATED;
-    }else
-        list_add_tail(&This->queued_buffers, &buf->entry);
-    This->public_buffer = NULL;
-
     OSSpinLockUnlock(&This->lock);
 
     return S_OK;
@@ -2339,7 +2341,6 @@ static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
         IAudioCaptureClient *iface, UINT32 *frames)
 {
     ACImpl *This = impl_from_IAudioCaptureClient(iface);
-    HRESULT hr;
 
     TRACE("(%p)->(%p)\n", This, frames);
 
@@ -2348,11 +2349,16 @@ static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
 
     OSSpinLockLock(&This->lock);
 
-    hr = AudioCaptureClient_GetNextPacket(This, frames);
+    avail_update(This);
+
+    if(This->inbuf_frames >= This->period_frames)
+        *frames = This->period_frames;
+    else
+        *frames = 0;
 
     OSSpinLockUnlock(&This->lock);
 
-    return hr;
+    return S_OK;
 }
 
 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
-- 
1.8.3.4





More information about the wine-patches mailing list