示例#1
0
static BOOL AppReadDataFromBuffer(LPDIRECTSOUNDCAPTUREBUFFER lpDsb, // The buffer.
				  DWORD dwOffset,		    // Our own write cursor.
				  LPBYTE lpbSoundData,		    // Start of our data.
				  DWORD dwSoundBytes)		    // Size of block to copy.
{ 
    LPVOID  lpvPtr1; 
    DWORD dwBytes1; 
    LPVOID  lpvPtr2; 
    DWORD dwBytes2; 
    HRESULT hr; 
    
    // Obtain memory address of write block. This will be in two parts
    // if the block wraps around.
    
    hr = IDirectSoundCaptureBuffer_Lock( lpDsb, dwOffset, dwSoundBytes, &lpvPtr1, 
					 &dwBytes1, &lpvPtr2, &dwBytes2, 0); 
    
    if SUCCEEDED(hr) { 
	// Read from pointers. 
	pj_memcpy(lpbSoundData, lpvPtr1, dwBytes1); 
	if (lpvPtr2 != NULL)
	    pj_memcpy(lpbSoundData+dwBytes1, lpvPtr2, dwBytes2); 
	
	// Release the data back to DirectSound. 
	hr = IDirectSoundCaptureBuffer_Unlock(lpDsb, lpvPtr1, dwBytes1, lpvPtr2, dwBytes2); 
	if SUCCEEDED(hr)
	    return TRUE; 
    } 
    
    // Lock, Unlock, or Restore failed. 
    return FALSE; 
}
示例#2
0
static int capture_buffer_service(capture_state_t* state)
{
    HRESULT rc;
    LPVOID ptr1,ptr2;
    DWORD len1,len2;
    DWORD capture_pos,read_pos;

    rc=IDirectSoundCaptureBuffer_GetCurrentPosition(state->dscbo,&capture_pos,
                                                    &read_pos);
    ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetCurrentPosition() failed: %08x\n", rc);
    if (rc!=DS_OK)
	return 0;

    rc=IDirectSoundCaptureBuffer_Lock(state->dscbo,state->offset,state->size,
                                      &ptr1,&len1,&ptr2,&len2,0);
    ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Lock() failed: %08x\n", rc);
    if (rc!=DS_OK)
	return 0;

    rc=IDirectSoundCaptureBuffer_Unlock(state->dscbo,ptr1,len1,ptr2,len2);
    ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Unlock() failed: %08x\n", rc);
    if (rc!=DS_OK)
	return 0;

    state->offset = (state->offset + state->size) % state->buffer_size;

    return 1;
}
示例#3
0
/*minsamples is a hint*/
unsigned int DSOUND_Capture_Update(void *ctx, unsigned char *buffer, unsigned int minbytes, unsigned int maxbytes)
{
	dsndcapture_t *c = ctx;
	HRESULT hr;
	LPBYTE lpbuf1 = NULL;
	LPBYTE lpbuf2 = NULL;
	DWORD dwsize1 = 0;
	DWORD dwsize2 = 0;

	DWORD capturePos;
	DWORD readPos;
	long  filled;

// Query to see how much data is in buffer.
	hr = IDirectSoundCaptureBuffer_GetCurrentPosition(c->DSCaptureBuffer, &capturePos, &readPos);
	if (hr != DS_OK)
	{
		return 0;
	}
	filled = readPos - c->lastreadpos;
	if (filled < 0)
		filled += bufferbytes; // unwrap offset

	if (filled > maxbytes)	//figure out how much we need to empty it by, and if that's enough to be worthwhile.
		filled = maxbytes;
	else if (filled < minbytes)
		return 0;

//	filled /= inputwidth;
//	filled *= inputwidth;

	// Lock free space in the DS
	hr = IDirectSoundCaptureBuffer_Lock(c->DSCaptureBuffer, c->lastreadpos, filled, (void **) &lpbuf1, &dwsize1, (void **) &lpbuf2, &dwsize2, 0);
	if (hr == DS_OK)
	{
		// Copy from DS to the buffer
		memcpy(buffer, lpbuf1, dwsize1);
		if(lpbuf2 != NULL)
		{
			memcpy(buffer+dwsize1, lpbuf2, dwsize2);
		}
		// Update our buffer offset and unlock sound buffer
 		c->lastreadpos = (c->lastreadpos + dwsize1 + dwsize2) % bufferbytes;
		IDirectSoundCaptureBuffer_Unlock(c->DSCaptureBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
	}
	else
	{
		return 0;
	}
	return filled;
}
static void *__playback_thread(void *param)
{
	tdav_producer_dsound_t* dsound = (tdav_producer_dsound_t*)param; 

	HRESULT hr;
	LPVOID lpvAudio1, lpvAudio2;
	DWORD dwBytesAudio1, dwBytesAudio2;

	TSK_DEBUG_INFO("__record_thread -- START");

	SetPriorityClass(GetCurrentThread(), REALTIME_PRIORITY_CLASS);

	for(;;){
		DWORD dwEvent = WaitForMultipleObjects(sizeof(dsound->notifEvents)/sizeof(HANDLE), dsound->notifEvents, FALSE, INFINITE);

		if(!dsound->started){
			break;
		}
		else {
			// lock
			if((hr = IDirectSoundCaptureBuffer_Lock(dsound->captureBuffer, (dwEvent * dsound->bytes_per_notif), dsound->bytes_per_notif, &lpvAudio1, &dwBytesAudio1, &lpvAudio2, &dwBytesAudio2, 0)) != DS_OK){
				tdav_win32_print_error("IDirectSoundCaptureBuffer_Lock", hr);
				goto next;
			}

			if(TMEDIA_PRODUCER(dsound)->enc_cb.callback){
				if(lpvAudio2){
					TMEDIA_PRODUCER(dsound)->enc_cb.callback(TMEDIA_PRODUCER(dsound)->enc_cb.callback_data, lpvAudio1, dwBytesAudio1);
					TMEDIA_PRODUCER(dsound)->enc_cb.callback(TMEDIA_PRODUCER(dsound)->enc_cb.callback_data, lpvAudio2, dwBytesAudio2);
				}
				else{
					TMEDIA_PRODUCER(dsound)->enc_cb.callback(TMEDIA_PRODUCER(dsound)->enc_cb.callback_data, lpvAudio1, dwBytesAudio1);
				}
			}

			// unlock
			if((hr = IDirectSoundCaptureBuffer_Unlock(dsound->captureBuffer, lpvAudio1, dwBytesAudio1, lpvAudio2, dwBytesAudio2)) != DS_OK){
				tdav_win32_print_error("IDirectSoundCaptureBuffer_Unlock", hr);
				goto next;
			}
next:;
		}
	}

	TSK_DEBUG_INFO("__record_thread -- STOP");
	

	return tsk_null;
}
示例#5
0
static ALCuint DSoundAvailableSamples(ALCdevice *pDevice)
{
    DSoundCaptureData *pData = pDevice->ExtraData;
    DWORD dwRead, dwCursor, dwBufferBytes, dwNumBytes;
    void *pvAudio1, *pvAudio2;
    DWORD dwAudioBytes1, dwAudioBytes2;
    DWORD FrameSize;
    HRESULT hr;

    if(!pDevice->Connected)
        goto done;

    FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
    dwBufferBytes = pData->dwBufferBytes;
    dwCursor = pData->dwCursor;

    hr = IDirectSoundCaptureBuffer_GetCurrentPosition(pData->DSCbuffer, NULL, &dwRead);
    if(SUCCEEDED(hr))
    {
        dwNumBytes = (dwBufferBytes + dwRead - dwCursor) % dwBufferBytes;
        if(dwNumBytes == 0)
            goto done;
        hr = IDirectSoundCaptureBuffer_Lock(pData->DSCbuffer,
                                            dwCursor, dwNumBytes,
                                            &pvAudio1, &dwAudioBytes1,
                                            &pvAudio2, &dwAudioBytes2, 0);
    }
    if(SUCCEEDED(hr))
    {
        WriteRingBuffer(pData->pRing, pvAudio1, dwAudioBytes1/FrameSize);
        if(pvAudio2 != NULL)
            WriteRingBuffer(pData->pRing, pvAudio2, dwAudioBytes2/FrameSize);
        hr = IDirectSoundCaptureBuffer_Unlock(pData->DSCbuffer,
                                              pvAudio1, dwAudioBytes1,
                                              pvAudio2, dwAudioBytes2);
        pData->dwCursor = (dwCursor + dwAudioBytes1 + dwAudioBytes2) % dwBufferBytes;
    }

    if(FAILED(hr))
    {
        ERR("update failed: 0x%08lx\n", hr);
        aluHandleDisconnect(pDevice);
    }

done:
    return RingBufferSize(pData->pRing);
}
示例#6
0
static ALCuint DSoundAvailableSamples(ALCdevice *Device)
{
    DSoundCaptureData *data = Device->ExtraData;
    DWORD ReadCursor, LastCursor, BufferBytes, NumBytes;
    VOID *ReadPtr1, *ReadPtr2;
    DWORD ReadCnt1,  ReadCnt2;
    DWORD FrameSize;
    HRESULT hr;

    if(!Device->Connected)
        goto done;

    FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
    BufferBytes = data->BufferBytes;
    LastCursor = data->Cursor;

    hr = IDirectSoundCaptureBuffer_GetCurrentPosition(data->DSCbuffer, NULL, &ReadCursor);
    if(SUCCEEDED(hr))
    {
        NumBytes = (ReadCursor-LastCursor + BufferBytes) % BufferBytes;
        if(NumBytes == 0)
            goto done;
        hr = IDirectSoundCaptureBuffer_Lock(data->DSCbuffer, LastCursor, NumBytes,
                                            &ReadPtr1, &ReadCnt1,
                                            &ReadPtr2, &ReadCnt2, 0);
    }
    if(SUCCEEDED(hr))
    {
        WriteRingBuffer(data->Ring, ReadPtr1, ReadCnt1/FrameSize);
        if(ReadPtr2 != NULL)
            WriteRingBuffer(data->Ring, ReadPtr2, ReadCnt2/FrameSize);
        hr = IDirectSoundCaptureBuffer_Unlock(data->DSCbuffer,
                                              ReadPtr1, ReadCnt1,
                                              ReadPtr2, ReadCnt2);
        data->Cursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes;
    }

    if(FAILED(hr))
    {
        ERR("update failed: 0x%08lx\n", hr);
        aluHandleDisconnect(Device);
    }

done:
    return RingBufferSize(data->Ring);
}
示例#7
0
static int
DSOUND_CaptureFromDevice(_THIS, void *buffer, int buflen)
{
    struct SDL_PrivateAudioData *h = this->hidden;
    DWORD junk, cursor, ptr1len, ptr2len;
    VOID *ptr1, *ptr2;

    SDL_assert(buflen == this->spec.size);

    while (SDL_TRUE) {
        if (SDL_AtomicGet(&this->shutdown)) {  /* in case the buffer froze... */
            SDL_memset(buffer, this->spec.silence, buflen);
            return buflen;
        }

        if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) != DS_OK) {
            return -1;
        }
        if ((cursor / this->spec.size) == h->lastchunk) {
            SDL_Delay(1);  /* FIXME: find out how much time is left and sleep that long */
        } else {
            break;
        }
    }

    if (IDirectSoundCaptureBuffer_Lock(h->capturebuf, h->lastchunk * this->spec.size, this->spec.size, &ptr1, &ptr1len, &ptr2, &ptr2len, 0) != DS_OK) {
        return -1;
    }

    SDL_assert(ptr1len == this->spec.size);
    SDL_assert(ptr2 == NULL);
    SDL_assert(ptr2len == 0);

    SDL_memcpy(buffer, ptr1, ptr1len);

    if (IDirectSoundCaptureBuffer_Unlock(h->capturebuf, ptr1, ptr1len, ptr2, ptr2len) != DS_OK) {
        return -1;
    }

    h->lastchunk = (h->lastchunk + 1) % h->num_buffers;

    return ptr1len;
}
static void
gst_directsound_src_reset (GstAudioSrc * asrc)
{
  GstDirectSoundSrc *dsoundsrc;
  LPVOID pLockedBuffer = NULL;
  DWORD dwSizeBuffer = 0;

  GST_DEBUG_OBJECT (asrc, "reset directsoundsrc");

  dsoundsrc = GST_DIRECTSOUND_SRC (asrc);

  GST_DSOUND_LOCK (dsoundsrc);

  dsoundsrc->reset_while_sleeping = TRUE;
  /* Interrupt read sleep if required */
  if (dsoundsrc->read_wait_clock_id != NULL)
    gst_clock_id_unschedule (dsoundsrc->read_wait_clock_id);

  if (dsoundsrc->pDSBSecondary) {
    /*stop capturing */
    HRESULT hRes = IDirectSoundCaptureBuffer_Stop (dsoundsrc->pDSBSecondary);

    /*reset position */
    /*    hRes = IDirectSoundCaptureBuffer_SetCurrentPosition (dsoundsrc->pDSBSecondary, 0); */

    /*reset the buffer */
    hRes = IDirectSoundCaptureBuffer_Lock (dsoundsrc->pDSBSecondary,
        dsoundsrc->current_circular_offset, dsoundsrc->buffer_size,
        pLockedBuffer, &dwSizeBuffer, NULL, NULL, 0L);

    if (SUCCEEDED (hRes)) {
      memset (pLockedBuffer, 0, dwSizeBuffer);

      hRes =
          IDirectSoundCaptureBuffer_Unlock (dsoundsrc->pDSBSecondary,
          pLockedBuffer, dwSizeBuffer, NULL, 0);
    }
    dsoundsrc->current_circular_offset = 0;

  }

  GST_DSOUND_UNLOCK (dsoundsrc);
}
static void
gst_directsound_src_reset (GstAudioSrc * asrc)
{
  GstDirectSoundSrc *dsoundsrc;
  LPVOID pLockedBuffer = NULL;
  DWORD dwSizeBuffer = 0;

  GST_DEBUG_OBJECT (asrc, "reset directsoundsrc");

  dsoundsrc = GST_DIRECTSOUND_SRC (asrc);

#if 0
  IDirectSoundCaptureBuffer_Stop (dsoundsrc->pDSBSecondary);
#endif

  GST_DSOUND_LOCK (dsoundsrc);

  if (dsoundsrc->pDSBSecondary) {
    /*stop capturing */
    HRESULT hRes = IDirectSoundCaptureBuffer_Stop (dsoundsrc->pDSBSecondary);

    /*reset position */
    /*    hRes = IDirectSoundCaptureBuffer_SetCurrentPosition (dsoundsrc->pDSBSecondary, 0); */

    /*reset the buffer */
    hRes = IDirectSoundCaptureBuffer_Lock (dsoundsrc->pDSBSecondary,
        dsoundsrc->current_circular_offset, dsoundsrc->buffer_size,
        pLockedBuffer, &dwSizeBuffer, NULL, NULL, 0L);

    if (SUCCEEDED (hRes)) {
      memset (pLockedBuffer, 0, dwSizeBuffer);

      hRes =
          IDirectSoundCaptureBuffer_Unlock (dsoundsrc->pDSBSecondary,
          pLockedBuffer, dwSizeBuffer, NULL, 0);
    }
    dsoundsrc->current_circular_offset = 0;

  }

  GST_DSOUND_UNLOCK (dsoundsrc);
}
示例#10
0
HRESULT DSW_ReadBlock( DSoundWrapper *dsw, char *buf, long numBytes )
{
	HRESULT hr;
	LPBYTE lpbuf1 = NULL;
	LPBYTE lpbuf2 = NULL;
	DWORD dwsize1 = 0;
	DWORD dwsize2 = 0;
	// Lock free space in the DS
	hr = IDirectSoundCaptureBuffer_Lock ( dsw->dsw_InputBuffer, dsw->dsw_ReadOffset, numBytes, (void **) &lpbuf1, &dwsize1,
		(void **) &lpbuf2, &dwsize2, 0);
	if (hr == DS_OK)
	{
		// Copy from DS to the buffer
		CopyMemory( buf, lpbuf1, dwsize1);
		if(lpbuf2 != NULL)
		{
			CopyMemory( buf+dwsize1, lpbuf2, dwsize2);
		}
		// Update our buffer offset and unlock sound buffer
 		dsw->dsw_ReadOffset = (dsw->dsw_ReadOffset + dwsize1 + dwsize2) % dsw->dsw_InputSize;
		IDirectSoundCaptureBuffer_Unlock ( dsw->dsw_InputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
	}
	return hr;
}
/* 
return number of readed bytes */
static guint
gst_directsound_src_read (GstAudioSrc * asrc, gpointer data, guint length,
    GstClockTime * timestamp)
{
  GstDirectSoundSrc *dsoundsrc;

  HRESULT hRes;                 /* Result for windows functions */
  DWORD dwCurrentCaptureCursor = 0;
  DWORD dwBufferSize = 0;

  LPVOID pLockedBuffer1 = NULL;
  LPVOID pLockedBuffer2 = NULL;
  DWORD dwSizeBuffer1 = 0;
  DWORD dwSizeBuffer2 = 0;

  DWORD dwStatus = 0;

  GST_DEBUG_OBJECT (asrc, "reading directsoundsrc");

  dsoundsrc = GST_DIRECTSOUND_SRC (asrc);

  GST_DSOUND_LOCK (dsoundsrc);

  /* Get current buffer status */
  hRes = IDirectSoundCaptureBuffer_GetStatus (dsoundsrc->pDSBSecondary,
      &dwStatus);

  /* Starting capturing if not already */
  if (!(dwStatus & DSCBSTATUS_CAPTURING)) {
    hRes = IDirectSoundCaptureBuffer_Start (dsoundsrc->pDSBSecondary,
        DSCBSTART_LOOPING);
    //    Sleep (dsoundsrc->latency_time/1000);
    GST_DEBUG_OBJECT (asrc, "capture started");
  }
  //  calculate_buffersize:
  while (length > dwBufferSize) {
    Sleep (dsoundsrc->latency_time / 1000);

    hRes =
        IDirectSoundCaptureBuffer_GetCurrentPosition (dsoundsrc->pDSBSecondary,
        &dwCurrentCaptureCursor, NULL);

    /* calculate the buffer */
    if (dwCurrentCaptureCursor < dsoundsrc->current_circular_offset) {
      dwBufferSize = dsoundsrc->buffer_size -
          (dsoundsrc->current_circular_offset - dwCurrentCaptureCursor);
    } else {
      dwBufferSize =
          dwCurrentCaptureCursor - dsoundsrc->current_circular_offset;
    }
  }                             // while (...

  /* Lock the buffer */
  hRes = IDirectSoundCaptureBuffer_Lock (dsoundsrc->pDSBSecondary,
      dsoundsrc->current_circular_offset,
      length,
      &pLockedBuffer1, &dwSizeBuffer1, &pLockedBuffer2, &dwSizeBuffer2, 0L);

  /* Copy buffer data to another buffer */
  if (hRes == DS_OK) {
    memcpy (data, pLockedBuffer1, dwSizeBuffer1);
  }

  /* ...and if something is in another buffer */
  if (pLockedBuffer2 != NULL) {
    memcpy (((guchar *) data + dwSizeBuffer1), pLockedBuffer2, dwSizeBuffer2);
  }

  dsoundsrc->current_circular_offset += dwSizeBuffer1 + dwSizeBuffer2;
  dsoundsrc->current_circular_offset %= dsoundsrc->buffer_size;

  IDirectSoundCaptureBuffer_Unlock (dsoundsrc->pDSBSecondary,
      pLockedBuffer1, dwSizeBuffer1, pLockedBuffer2, dwSizeBuffer2);

  GST_DSOUND_UNLOCK (dsoundsrc);

  /* return length (readed data size in bytes) */
  return length;
}
示例#12
0
// ////////////////////////////////////////////////////////////////////////
static BOOL sendAudioBuffer(BOOL bNow)
{
	DWORD			read;
	static DWORD	lastread=0;
	HRESULT			hr;
	NETMSG			msg;
	
	UWORD			size=0;

	LPVOID			lpvPtr1,lpvPtr2;
	DWORD			dwBytes1=0,dwBytes2=0;

	hr = IDirectSoundCaptureBuffer_GetCurrentPosition(lpDirectSoundCaptureBuffer,NULL,&read);
	if(hr != DS_OK)
	{
		return FALSE;
	}

	// if buffer is still pretty empty
	if(lastread <= read)		// non wrapped.
	{
		size = (UWORD) (read - lastread);
	}
	else					// wrapped
	{
		size = (UWORD) (read + (captureBuff.dwBufferBytes - lastread));
	}
	

	if(!bNow)
	{
		if(size < ((MaxMsgSize*3)/4)  )
		{
			return TRUE;
		}
	}

	// send an audio packet if getting near the end of the buffer.
	if(size > MaxMsgSize)
	{
		size = MaxMsgSize;
		DBPRINTF(("NETPLAY:lost some audio\n"));
	}

	// lock an area
	hr = IDirectSoundCaptureBuffer_Lock(lpDirectSoundCaptureBuffer, //Obtain mem add. of write block.
							 lastread,							// start at
							 size,								// read this much
							 &lpvPtr1,&dwBytes1,										
							 &lpvPtr2,&dwBytes2,	
							 0									//DSCBLOCK_ENTIREBUFFER	
							);

	lastread = lastread+size;
	if(lastread >captureBuff.dwBufferBytes)						// wrapped
	{
		lastread = lastread - captureBuff.dwBufferBytes;
	}
	

	if(hr != DS_OK)
	{
		return FALSE;
	}

	// read it out
	memcpy(msg.body,lpvPtr1,dwBytes1);							// copy first part into buffer

	if (lpvPtr2 != NULL)										// second part.
	{
		memcpy(((UBYTE *)msg.body)+dwBytes1,lpvPtr2,dwBytes2);	// buffer contents			
	}
		
	// unlock area.
	hr =  IDirectSoundCaptureBuffer_Unlock(lpDirectSoundCaptureBuffer,  
										lpvPtr1,dwBytes1,
										lpvPtr2,dwBytes2);
	if(hr != DS_OK)
	{
		return FALSE;
	}
	
	// may want to compress it! 
//MMRESULT acmFormatSuggest( HACMDRIVER had, LPWAVEFORMATEX pwfxSrc, LPWAVEFORMATEX pwfxDst, DWORD cbwfxDst, DWORD fdwSuggest 
  

	
	// send the buffer elsewhere
	msg.type = AUDIOMSG;
	msg.size = (UWORD)(dwBytes1+dwBytes2);
	NETbcast(&msg,FALSE);

	return TRUE;
}
示例#13
0
/* 
return number of readed bytes */
static guint
gst_directsound_src_read (GstAudioSrc * asrc, gpointer data, guint length,
    GstClockTime * timestamp)
{
  GstDirectSoundSrc *dsoundsrc;
  guint64 sleep_time_ms, sleep_until;
  GstClockID clock_id;

  HRESULT hRes;                 /* Result for windows functions */
  DWORD dwCurrentCaptureCursor = 0;
  DWORD dwBufferSize = 0;

  LPVOID pLockedBuffer1 = NULL;
  LPVOID pLockedBuffer2 = NULL;
  DWORD dwSizeBuffer1 = 0;
  DWORD dwSizeBuffer2 = 0;

  DWORD dwStatus = 0;

  GST_DEBUG_OBJECT (asrc, "reading directsoundsrc");

  dsoundsrc = GST_DIRECTSOUND_SRC (asrc);

  GST_DSOUND_LOCK (dsoundsrc);

  /* Get current buffer status */
  hRes = IDirectSoundCaptureBuffer_GetStatus (dsoundsrc->pDSBSecondary,
      &dwStatus);

  if (FAILED (hRes)) {
    GST_DSOUND_UNLOCK (dsoundsrc);
    return -1;
  }

  /* Starting capturing if not already */
  if (!(dwStatus & DSCBSTATUS_CAPTURING)) {
    hRes = IDirectSoundCaptureBuffer_Start (dsoundsrc->pDSBSecondary,
        DSCBSTART_LOOPING);
    GST_INFO_OBJECT (asrc, "capture started");
  }

  /* Loop till the source has produced bytes equal to or greater than @length.
   *
   * DirectSound has a notification-based API that uses Windows CreateEvent()
   * + WaitForSingleObject(), but it is completely useless for live streams.
   *
   *  1. You must schedule all events before starting capture
   *  2. The events are all fired exactly once
   *  3. You cannot schedule new events while a capture is running
   *  4. You cannot stop/schedule/start either
   *
   * This means you cannot use the API while doing live looped capture and we
   * must resort to this.
   *
   * However, this is almost as efficient as event-based capture since it's ok
   * to consistently overwait by a fixed amount; the extra bytes will just end
   * up being used in the next call, and the extra latency will be constant. */
  while (TRUE) {
    hRes =
        IDirectSoundCaptureBuffer_GetCurrentPosition (dsoundsrc->pDSBSecondary,
        &dwCurrentCaptureCursor, NULL);

    if (FAILED (hRes)) {
      GST_DSOUND_UNLOCK (dsoundsrc);
      return -1;
    }

    /* calculate the size of the buffer that's been captured while accounting
     * for wrap-arounds */
    if (dwCurrentCaptureCursor < dsoundsrc->current_circular_offset) {
      dwBufferSize = dsoundsrc->buffer_size -
          (dsoundsrc->current_circular_offset - dwCurrentCaptureCursor);
    } else {
      dwBufferSize =
          dwCurrentCaptureCursor - dsoundsrc->current_circular_offset;
    }

    if (dwBufferSize >= length) {
      /* Yay, we got all the data we need */
      break;
    } else {
      GST_DEBUG_OBJECT (asrc, "not enough data, got %lu (want at least %u)",
          dwBufferSize, length);
      /* If we didn't get enough data, sleep for a proportionate time */
      sleep_time_ms = gst_util_uint64_scale (dsoundsrc->latency_time,
          length - dwBufferSize, length * 1000);
      /* Make sure we don't run in a tight loop unnecessarily */
      sleep_time_ms = MAX (sleep_time_ms, 10);
      /* Sleep using gst_clock_id_wait() so that we can be interrupted */
      sleep_until = gst_clock_get_time (dsoundsrc->system_clock) +
          sleep_time_ms * GST_MSECOND;
      /* Setup the clock id wait */
      if (G_UNLIKELY (dsoundsrc->read_wait_clock_id == NULL ||
              gst_clock_single_shot_id_reinit (dsoundsrc->system_clock,
                  dsoundsrc->read_wait_clock_id, sleep_until) == FALSE)) {
        if (dsoundsrc->read_wait_clock_id != NULL)
          gst_clock_id_unref (dsoundsrc->read_wait_clock_id);
        dsoundsrc->read_wait_clock_id =
            gst_clock_new_single_shot_id (dsoundsrc->system_clock, sleep_until);
      }

      clock_id = dsoundsrc->read_wait_clock_id;
      dsoundsrc->reset_while_sleeping = FALSE;

      GST_DEBUG_OBJECT (asrc, "waiting %" G_GUINT64_FORMAT "ms for more data",
          sleep_time_ms);
      GST_DSOUND_UNLOCK (dsoundsrc);

      gst_clock_id_wait (clock_id, NULL);

      GST_DSOUND_LOCK (dsoundsrc);

      if (dsoundsrc->reset_while_sleeping == TRUE) {
        GST_DEBUG_OBJECT (asrc, "reset while sleeping, cancelled read");
        GST_DSOUND_UNLOCK (dsoundsrc);
        return -1;
      }
    }
  }

  GST_DEBUG_OBJECT (asrc, "Got enough data: %lu bytes (wanted at least %u)",
      dwBufferSize, length);

  /* Lock the buffer and read only the first @length bytes. Keep the rest in
   * the capture buffer for the next read. */
  hRes = IDirectSoundCaptureBuffer_Lock (dsoundsrc->pDSBSecondary,
      dsoundsrc->current_circular_offset,
      length,
      &pLockedBuffer1, &dwSizeBuffer1, &pLockedBuffer2, &dwSizeBuffer2, 0L);

  /* NOTE: We now assume that dwSizeBuffer1 + dwSizeBuffer2 == length since the
   * API is supposed to guarantee that */

  /* Copy buffer data to another buffer */
  if (hRes == DS_OK) {
    memcpy (data, pLockedBuffer1, dwSizeBuffer1);
  }

  /* ...and if something is in another buffer */
  if (pLockedBuffer2 != NULL) {
    memcpy (((guchar *) data + dwSizeBuffer1), pLockedBuffer2, dwSizeBuffer2);
  }

  dsoundsrc->current_circular_offset += dwSizeBuffer1 + dwSizeBuffer2;
  dsoundsrc->current_circular_offset %= dsoundsrc->buffer_size;

  IDirectSoundCaptureBuffer_Unlock (dsoundsrc->pDSBSecondary,
      pLockedBuffer1, dwSizeBuffer1, pLockedBuffer2, dwSizeBuffer2);

  GST_DSOUND_UNLOCK (dsoundsrc);

  /* We always read exactly @length data */
  return length;
}