Пример #1
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;
}
Пример #2
0
static guint
gst_directsound_src_delay (GstAudioSrc * asrc)
{
  GstDirectSoundSrc *dsoundsrc;
  HRESULT hRes;
  DWORD dwCurrentCaptureCursor;
  DWORD dwBytesInQueue = 0;
  gint nNbSamplesInQueue = 0;

  GST_DEBUG_OBJECT (asrc, "Delay");

  dsoundsrc = GST_DIRECTSOUND_SRC (asrc);

  /* evaluate the number of samples in queue in the circular buffer */
  hRes =
      IDirectSoundCaptureBuffer_GetCurrentPosition (dsoundsrc->pDSBSecondary,
      &dwCurrentCaptureCursor, NULL);
  /* FIXME: Check is this calculated right */
  if (hRes == S_OK) {
    if (dwCurrentCaptureCursor < dsoundsrc->current_circular_offset) {
      dwBytesInQueue =
          dsoundsrc->buffer_size - (dsoundsrc->current_circular_offset -
          dwCurrentCaptureCursor);
    } else {
      dwBytesInQueue =
          dwCurrentCaptureCursor - dsoundsrc->current_circular_offset;
    }

    nNbSamplesInQueue = dwBytesInQueue / dsoundsrc->bytes_per_sample;
  }

  return nNbSamplesInQueue;
}
Пример #3
0
void DSOUND_Capture_Start(void *ctx)
{
	DWORD capturePos;
	dsndcapture_t *c = ctx;
	IDirectSoundCaptureBuffer_Start(c->DSCaptureBuffer, DSBPLAY_LOOPING);

	c->lastreadpos = 0;
	IDirectSoundCaptureBuffer_GetCurrentPosition(c->DSCaptureBuffer, &capturePos, &c->lastreadpos);
}
Пример #4
0
static void
DSOUND_FlushCapture(_THIS)
{
    struct SDL_PrivateAudioData *h = this->hidden;
    DWORD junk, cursor;
    if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) == DS_OK) {
        h->lastchunk = cursor / this->spec.size;
    }
}
Пример #5
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;
}
Пример #6
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);
}
Пример #7
0
static int dsound_run_in (HWVoiceIn *hw)
{
    int err;
    HRESULT hr;
    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
    LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
    int live, len, dead;
    DWORD blen1, blen2;
    DWORD len1, len2;
    DWORD decr;
    DWORD cpos, rpos;
    LPVOID p1, p2;
    int hwshift;
    dsound *s = ds->s;

    if (!dscb) {
        dolog ("Attempt to run without capture buffer\n");
        return 0;
    }

    hwshift = hw->info.shift;

    live = audio_pcm_hw_get_live_in (hw);
    dead = hw->samples - live;
    if (!dead) {
        return 0;
    }

    hr = IDirectSoundCaptureBuffer_GetCurrentPosition (
        dscb,
        &cpos,
        ds->first_time ? &rpos : NULL
        );
    if (FAILED (hr)) {
        dsound_logerr (hr, "Could not get capture buffer position\n");
        return 0;
    }

    if (ds->first_time) {
        ds->first_time = 0;
        if (rpos & hw->info.align) {
            ldebug ("warning: Misaligned capture read position %ld(%d)\n",
                    rpos, hw->info.align);
        }
        hw->wpos = rpos >> hwshift;
    }
Пример #8
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);
}
Пример #9
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;
}
Пример #10
0
HRESULT DSW_QueryInputFilled( DSoundWrapper *dsw, long *bytesFilled )
{
	HRESULT hr;
	DWORD capturePos;
	DWORD readPos;
	long  filled;
// Query to see how much data is in buffer.
// We don't need the capture position but sometimes DirectSound doesn't handle NULLS correctly
// so let's pass a pointer just to be safe.
	hr = IDirectSoundCaptureBuffer_GetCurrentPosition( dsw->dsw_InputBuffer, &capturePos, &readPos );
	if( hr != DS_OK )
	{
		return hr;
	}
	filled = readPos - dsw->dsw_ReadOffset;
	if( filled < 0 ) filled += dsw->dsw_InputSize; // unwrap offset
	*bytesFilled = filled;
	return hr;
}
Пример #11
0
/*
 * Check if there are captured frames in DirectSound capture buffer.
 */
static unsigned dsound_captured_size(struct dsound_stream *dsound_strm)
{
    HRESULT hr;
    long size_available;
    DWORD writePos, readPos;

    hr = IDirectSoundCaptureBuffer_GetCurrentPosition(
					dsound_strm->ds.capture.lpDsBuffer, 
					&writePos, &readPos);
    if FAILED(hr)
	return PJ_FALSE;

    if (readPos < dsound_strm->dwBytePos)
	size_available = readPos +
		    (dsound_strm->dwDsBufferSize) - dsound_strm->dwBytePos;
    else
	size_available = readPos - dsound_strm->dwBytePos;

    return size_available;
}
Пример #12
0
/* This function tries to create a capture buffer, and returns the
   number of audio chunks available in the created buffer. This is for
   capture devices, not playback.
*/
static int
CreateCaptureBuffer(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt)
{
    LPDIRECTSOUNDCAPTURE capture = this->hidden->capture;
    LPDIRECTSOUNDCAPTUREBUFFER *capturebuf = &this->hidden->capturebuf;
    DSCBUFFERDESC format;
//    DWORD junk, cursor;
    HRESULT result;

    SDL_zero(format);
    format.dwSize = sizeof (format);
    format.dwFlags = DSCBCAPS_WAVEMAPPED;
    format.dwBufferBytes = bufsize;
    format.lpwfxFormat = wfmt;

    result = IDirectSoundCapture_CreateCaptureBuffer(capture, &format, capturebuf, NULL);
    if (result != DS_OK) {
        return SetDSerror("DirectSound CreateCaptureBuffer", result);
    }

    result = IDirectSoundCaptureBuffer_Start(*capturebuf, DSCBSTART_LOOPING);
    if (result != DS_OK) {
        IDirectSoundCaptureBuffer_Release(*capturebuf);
        return SetDSerror("DirectSound Start", result);
    }

#if 0
    /* presumably this starts at zero, but just in case... */
    result = IDirectSoundCaptureBuffer_GetCurrentPosition(*capturebuf, &junk, &cursor);
    if (result != DS_OK) {
        IDirectSoundCaptureBuffer_Stop(*capturebuf);
        IDirectSoundCaptureBuffer_Release(*capturebuf);
        return SetDSerror("DirectSound GetCurrentPosition", result);
    }

    this->hidden->lastchunk = cursor / this->spec.size;
#endif

    return 0;
}
Пример #13
0
/*
 * Start stream.
 */
PJ_DEF(pj_status_t) pjmedia_snd_stream_start(pjmedia_snd_stream *stream)
{
    HRESULT hr;

    if (stream->play_strm.ds.play.lpDsBuffer) {
	hr = IDirectSoundBuffer_SetCurrentPosition(
				stream->play_strm.ds.play.lpDsBuffer, 0);
	if (FAILED(hr))
	    return PJ_RETURN_OS_ERROR(hr);
	
	/* Set the write pointer ahead of the read pointer by latency bytes */
	stream->play_strm.dwBytePos = BYTES_PER_SAMPLE * stream->clock_rate *
		stream->channel_count * stream->play_strm.latency / 1000;

	hr = IDirectSoundBuffer_Play(stream->play_strm.ds.play.lpDsBuffer, 
				     0, 0, DSBPLAY_LOOPING);
	if (FAILED(hr))
	    return PJ_RETURN_OS_ERROR(hr);
	PJ_LOG(5,(THIS_FILE, "DirectSound playback stream started"));
    }
    
    if (stream->rec_strm.ds.capture.lpDsBuffer) {
	hr = IDirectSoundCaptureBuffer_GetCurrentPosition( 
				stream->rec_strm.ds.capture.lpDsBuffer, 
				NULL, &stream->rec_strm.dwBytePos );
	if (FAILED(hr))
	    return PJ_RETURN_OS_ERROR(hr);

	hr = IDirectSoundCaptureBuffer_Start(
				stream->rec_strm.ds.capture.lpDsBuffer,
				DSCBSTART_LOOPING );
	if (FAILED(hr))
	    return PJ_RETURN_OS_ERROR(hr);
	PJ_LOG(5,(THIS_FILE, "DirectSound capture stream started"));
    }

    return PJ_SUCCESS;
}
Пример #14
0
/*
 * Initialize DirectSound recorder device
 */
static pj_status_t init_capture_stream( struct dsound_stream *ds_strm,
				        int dev_id,
				        unsigned clock_rate,
				        unsigned channel_count,
				        unsigned samples_per_frame,
				        unsigned buffer_count)
{
    HRESULT hr;
    PCMWAVEFORMAT pcmwf; 
    DSCBUFFERDESC dscbdesc;
    DSBPOSITIONNOTIFY dsPosNotify[MAX_PACKET_BUFFER_COUNT];
    unsigned bytes_per_frame;
    unsigned i;


    PJ_ASSERT_RETURN(buffer_count <= MAX_PACKET_BUFFER_COUNT, PJ_EINVAL);


    /* Check device id */
    if (dev_id == -1)
	dev_id = 0;

    PJ_ASSERT_RETURN(dev_id>=0 && dev_id < (int)dev_count, PJ_EINVAL);

    /*
     * Creating recorder device.
     */
    hr = DirectSoundCaptureCreate(dev_info[dev_id].lpGuid, 
				  &ds_strm->ds.capture.lpDs, NULL);
    if (FAILED(hr))
	return PJ_RETURN_OS_ERROR(hr);


    /* Init wave format to initialize buffer */
    init_waveformatex( &pcmwf, clock_rate, channel_count);
    bytes_per_frame = samples_per_frame * BYTES_PER_SAMPLE;

    /* 
     * Setup capture buffer using sound buffer structure that was passed
     * to play buffer creation earlier.
     */
    pj_bzero(&dscbdesc, sizeof(DSCBUFFERDESC));
    dscbdesc.dwSize = sizeof(DSCBUFFERDESC); 
    dscbdesc.dwFlags = DSCBCAPS_WAVEMAPPED ;
    dscbdesc.dwBufferBytes = buffer_count * bytes_per_frame; 
    dscbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf; 

    hr = IDirectSoundCapture_CreateCaptureBuffer( ds_strm->ds.capture.lpDs,
						  &dscbdesc, 
						  &ds_strm->ds.capture.lpDsBuffer,
						  NULL);
    if (FAILED(hr))
	return PJ_RETURN_OS_ERROR(hr);

    /*
     * Create event for play notification.
     */
    ds_strm->hEvent = CreateEvent( NULL, FALSE, FALSE, NULL);
    if (ds_strm->hEvent == NULL)
	return pj_get_os_error();

    /*
     * Setup notifications for recording.
     */
    hr = IDirectSoundCaptureBuffer_QueryInterface( ds_strm->ds.capture.lpDsBuffer, 
						   &IID_IDirectSoundNotify, 
						   (LPVOID *)&ds_strm->lpDsNotify); 
    if (FAILED(hr))
	return PJ_RETURN_OS_ERROR(hr);

    
    for (i=0; i<buffer_count; ++i) {
	dsPosNotify[i].dwOffset = i * bytes_per_frame;
	dsPosNotify[i].hEventNotify = ds_strm->hEvent;
    }
    
    hr = IDirectSoundNotify_SetNotificationPositions( ds_strm->lpDsNotify, 
						      buffer_count, 
						      dsPosNotify);
    if (FAILED(hr))
	return PJ_RETURN_OS_ERROR(hr);

    hr = IDirectSoundCaptureBuffer_GetCurrentPosition( ds_strm->ds.capture.lpDsBuffer, 
						       NULL, &ds_strm->dwBytePos );
    if (FAILED(hr))
	return PJ_RETURN_OS_ERROR(hr);

    ds_strm->timestamp.u64 = 0;
    ds_strm->dwDsBufferSize = buffer_count * bytes_per_frame;
    /*
     * Capture latency must always be on a frame boundry,
     * so compute it based off the calculated buffer_count.
     */
    ds_strm->latency = buffer_count * samples_per_frame * 1000 / clock_rate / 
		       channel_count;

    /* Done setting up recorder device. */
    PJ_LOG(5,(THIS_FILE, 
	      " DirectSound capture \"%s\" initialized (clock_rate=%d, "
	      "channel_count=%d, samples_per_frame=%d (%dms))",
	      dev_info[dev_id].info.name,
	      clock_rate, channel_count, samples_per_frame,
	      samples_per_frame * 1000 / clock_rate));

    return PJ_SUCCESS;
}
Пример #15
0
/* 
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;
}
Пример #16
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;
}
Пример #17
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;
}