static void gst_directsound_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstDirectSoundSrc * src = GST_DIRECTSOUND_SRC (object); switch (prop_id) { /*case ARG_VOLUME: sink->volume = g_value_get_double (value); gst_directsound_sink_set_volume (sink); break;*/ case ARG_DEVICE: if (src->device_id) { g_free (src->device_id); src->device_id = NULL; } if (src->device_name) { g_free (src->device_name); src->device_name = NULL; } src->device_id = g_strdup (g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void gst_directsound_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstDirectSoundSrc *src = GST_DIRECTSOUND_SRC (object); GST_DEBUG ("set property"); switch (prop_id) { case PROP_DEVICE_NAME: if (src->device_name) { g_free (src->device_name); src->device_name = NULL; } if (g_value_get_string (value)) { src->device_name = g_strdup (g_value_get_string (value)); } break; case PROP_VOLUME: gst_directsound_src_set_volume (src, g_value_get_double (value)); break; case PROP_MUTE: gst_directsound_src_set_mute (src, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
/* GstBaseAudioSrc vmethod implementations */ static GstRingBuffer * gst_directsound_src_create_ringbuffer (GstBaseAudioSrc * src) { GstDirectSoundSrc * dsoundsrc; GstDirectSoundRingBuffer * ringbuffer; dsoundsrc = GST_DIRECTSOUND_SRC (src); GST_DEBUG ("creating ringbuffer"); ringbuffer = g_object_new (GST_TYPE_DIRECTSOUND_RING_BUFFER, NULL); GST_DEBUG ("directsound src 0x%p", dsoundsrc); /* capture */ ringbuffer->is_src = TRUE; /* set the src element on the ringbuffer for error messages */ ringbuffer->element = GST_ELEMENT (dsoundsrc); /* set the ringbuffer on the src */ dsoundsrc->dsoundbuffer = ringbuffer; /* set initial volume on ringbuffer */ dsoundsrc->dsoundbuffer->volume = dsoundsrc->volume; return GST_RING_BUFFER (ringbuffer); }
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; }
static void gst_directsound_src_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstDirectSoundSrc * src = GST_DIRECTSOUND_SRC (object); switch (prop_id) { /*case ARG_VOLUME: g_value_set_double (value, sink->volume); break;*/ case ARG_DEVICE: if (!src->device_id) device_set_default (src); g_value_set_string (value, src->device_id); break; case ARG_DEVICE_NAME: if (!src->device_name) device_get_name (src); g_value_set_string (value, src->device_name); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void gst_directsound_src_finalize (GObject * object) { GstDirectSoundSrc *dsoundsrc = GST_DIRECTSOUND_SRC (object); g_mutex_clear (&dsoundsrc->dsound_lock); g_free (dsoundsrc->device_name); g_free (dsoundsrc->device_guid); G_OBJECT_CLASS (parent_class)->finalize (object); }
static gboolean gst_directsound_src_unprepare (GstAudioSrc * asrc) { GstDirectSoundSrc *dsoundsrc; GST_DEBUG_OBJECT (asrc, "unpreparing directsoundsrc"); dsoundsrc = GST_DIRECTSOUND_SRC (asrc); /* Stop capturing */ IDirectSoundCaptureBuffer_Stop (dsoundsrc->pDSBSecondary); /* Release buffer */ IDirectSoundCaptureBuffer_Release (dsoundsrc->pDSBSecondary); return TRUE; }
static void gst_directsound_src_dispose (GObject * object) { GstDirectSoundSrc * self = GST_DIRECTSOUND_SRC (object); GST_DEBUG_OBJECT (object, G_STRFUNC); if (self->device_id) { g_free (self->device_id); self->device_id = NULL; } if (self->device_name) { g_free (self->device_name); self->device_name = NULL; } G_OBJECT_CLASS (parent_class)->dispose (object); }
static void gst_directsound_src_finalize (GObject * object) { GstDirectSoundSrc *dsoundsrc = GST_DIRECTSOUND_SRC (object); g_mutex_clear (&dsoundsrc->dsound_lock); gst_object_unref (dsoundsrc->system_clock); if (dsoundsrc->read_wait_clock_id != NULL) gst_clock_id_unref (dsoundsrc->read_wait_clock_id); g_free (dsoundsrc->device_name); g_free (dsoundsrc->device_id); g_free (dsoundsrc->device_guid); G_OBJECT_CLASS (parent_class)->finalize (object); }
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); }
static gboolean gst_directsound_src_close (GstAudioSrc * asrc) { GstDirectSoundSrc *dsoundsrc; GST_DEBUG_OBJECT (asrc, "closing directsoundsrc"); dsoundsrc = GST_DIRECTSOUND_SRC (asrc); /* Release capture handler */ IDirectSoundCapture_Release (dsoundsrc->pDSC); /* Close library */ FreeLibrary (dsoundsrc->DSoundDLL); if (dsoundsrc->mixer) mixerClose (dsoundsrc->mixer); return TRUE; }
/* Enumeration callback called by DirectSoundCaptureEnumerate. * Gets the GUID of request audio device */ static BOOL CALLBACK gst_directsound_enum_callback (GUID * pGUID, TCHAR * strDesc, TCHAR * strDrvName, VOID * pContext) { GstDirectSoundSrc *dsoundsrc = GST_DIRECTSOUND_SRC (pContext); if (pGUID && dsoundsrc && dsoundsrc->device_name && !g_strcmp0 (dsoundsrc->device_name, strDesc)) { g_free (dsoundsrc->device_guid); dsoundsrc->device_guid = (GUID *) g_malloc0 (sizeof (GUID)); memcpy (dsoundsrc->device_guid, pGUID, sizeof (GUID)); GST_INFO_OBJECT (dsoundsrc, "found the requested audio device :%s", dsoundsrc->device_name); return FALSE; } GST_INFO_OBJECT (dsoundsrc, "sound device names: %s, %s, requested device:%s", strDesc, strDrvName, dsoundsrc->device_name); return TRUE; }
/* Enumeration callback called by DirectSoundCaptureEnumerate. * Gets the GUID of request audio device */ static BOOL CALLBACK gst_directsound_enum_callback (GUID * pGUID, TCHAR * strDesc, TCHAR * strDrvName, VOID * pContext) { GstDirectSoundSrc *dsoundsrc = GST_DIRECTSOUND_SRC (pContext); gchar *driver, *description; description = g_locale_to_utf8 (strDesc, -1, NULL, NULL, NULL); if (!description) { GST_ERROR_OBJECT (dsoundsrc, "Failed to convert description from locale encoding to UTF8"); return TRUE; } driver = g_locale_to_utf8 (strDrvName, -1, NULL, NULL, NULL); if (pGUID && dsoundsrc && dsoundsrc->device_name && !g_strcmp0 (dsoundsrc->device_name, description)) { g_free (dsoundsrc->device_guid); dsoundsrc->device_guid = (GUID *) g_malloc0 (sizeof (GUID)); memcpy (dsoundsrc->device_guid, pGUID, sizeof (GUID)); GST_INFO_OBJECT (dsoundsrc, "found the requested audio device :%s", dsoundsrc->device_name); g_free (description); g_free (driver); return FALSE; } GST_INFO_OBJECT (dsoundsrc, "sound device names: %s, %s, requested device:%s", description, driver, dsoundsrc->device_name); g_free (description); g_free (driver); return TRUE; }
/* 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; }
/* 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; }
static gboolean gst_directsound_src_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec) { GstDirectSoundSrc *dsoundsrc; WAVEFORMATEX wfx; /* Wave format structure */ HRESULT hRes; /* Result for windows functions */ DSCBUFFERDESC descSecondary; /* Capturebuffer description */ dsoundsrc = GST_DIRECTSOUND_SRC (asrc); GST_DEBUG_OBJECT (asrc, "preparing directsoundsrc"); /* Define buffer */ memset (&wfx, 0, sizeof (WAVEFORMATEX)); wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nChannels = GST_AUDIO_INFO_CHANNELS (&spec->info); wfx.nSamplesPerSec = GST_AUDIO_INFO_RATE (&spec->info); wfx.wBitsPerSample = GST_AUDIO_INFO_BPF (&spec->info) * 8 / wfx.nChannels; wfx.nBlockAlign = GST_AUDIO_INFO_BPF (&spec->info); wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; /* Ignored for WAVE_FORMAT_PCM. */ wfx.cbSize = 0; if (wfx.wBitsPerSample != 16 && wfx.wBitsPerSample != 8) goto dodgy_width; /* Set the buffer size to two seconds. This should never reached. */ dsoundsrc->buffer_size = wfx.nAvgBytesPerSec * 2; GST_DEBUG_OBJECT (asrc, "Buffer size: %d", dsoundsrc->buffer_size); /* Init secondary buffer desciption */ memset (&descSecondary, 0, sizeof (DSCBUFFERDESC)); descSecondary.dwSize = sizeof (DSCBUFFERDESC); descSecondary.dwFlags = 0; descSecondary.dwReserved = 0; /* This is not primary buffer so have to set size */ descSecondary.dwBufferBytes = dsoundsrc->buffer_size; descSecondary.lpwfxFormat = &wfx; /* Create buffer */ hRes = IDirectSoundCapture_CreateCaptureBuffer (dsoundsrc->pDSC, &descSecondary, &dsoundsrc->pDSBSecondary, NULL); if (hRes != DS_OK) goto capture_buffer; dsoundsrc->bytes_per_sample = GST_AUDIO_INFO_BPF (&spec->info); GST_DEBUG ("latency time: %" G_GUINT64_FORMAT " - buffer time: %" G_GUINT64_FORMAT, spec->latency_time, spec->buffer_time); /* Buffer-time should be always more than 2*latency */ if (spec->buffer_time < spec->latency_time * 2) { spec->buffer_time = spec->latency_time * 2; GST_WARNING ("buffer-time was less than latency"); } /* Save the times */ dsoundsrc->buffer_time = spec->buffer_time; dsoundsrc->latency_time = spec->latency_time; dsoundsrc->latency_size = (gint) wfx.nAvgBytesPerSec * dsoundsrc->latency_time / 1000000.0; spec->segsize = (guint) (((double) spec->buffer_time / 1000000.0) * wfx.nAvgBytesPerSec); /* just in case */ if (spec->segsize < 1) spec->segsize = 1; spec->segtotal = GST_AUDIO_INFO_BPF (&spec->info) * 8 * (wfx.nAvgBytesPerSec / spec->segsize); GST_DEBUG_OBJECT (asrc, "bytes/sec: %lu, buffer size: %d, segsize: %d, segtotal: %d", wfx.nAvgBytesPerSec, dsoundsrc->buffer_size, spec->segsize, spec->segtotal); /* Not read anything yet */ dsoundsrc->current_circular_offset = 0; GST_DEBUG_OBJECT (asrc, "channels: %d, rate: %d, bytes_per_sample: %d" " WAVEFORMATEX.nSamplesPerSec: %ld, WAVEFORMATEX.wBitsPerSample: %d," " WAVEFORMATEX.nBlockAlign: %d, WAVEFORMATEX.nAvgBytesPerSec: %ld", GST_AUDIO_INFO_CHANNELS (&spec->info), GST_AUDIO_INFO_RATE (&spec->info), GST_AUDIO_INFO_BPF (&spec->info), wfx.nSamplesPerSec, wfx.wBitsPerSample, wfx.nBlockAlign, wfx.nAvgBytesPerSec); return TRUE; capture_buffer: { GST_ELEMENT_ERROR (dsoundsrc, RESOURCE, OPEN_READ, ("Unable to create capturebuffer"), (NULL)); return FALSE; } dodgy_width: { GST_ELEMENT_ERROR (dsoundsrc, RESOURCE, OPEN_READ, ("Unexpected width %d", wfx.wBitsPerSample), (NULL)); return FALSE; } }
static gboolean gst_directsound_src_open (GstAudioSrc * asrc) { GstDirectSoundSrc *dsoundsrc; HRESULT hRes; /* Result for windows functions */ GST_DEBUG_OBJECT (asrc, "opening directsoundsrc"); dsoundsrc = GST_DIRECTSOUND_SRC (asrc); /* Open dsound.dll */ dsoundsrc->DSoundDLL = LoadLibrary ("dsound.dll"); if (!dsoundsrc->DSoundDLL) { goto dsound_open; } /* Building the DLL Calls */ pDSoundCaptureCreate = (void *) GetProcAddress (dsoundsrc->DSoundDLL, TEXT ("DirectSoundCaptureCreate")); /* If everything is not ok */ if (!pDSoundCaptureCreate) { goto capture_function; } hRes = DirectSoundCaptureEnumerate ((LPDSENUMCALLBACK) gst_directsound_enum_callback, (VOID *) dsoundsrc); if (FAILED (hRes)) { goto capture_enumerate; } /* Create capture object */ hRes = pDSoundCaptureCreate (dsoundsrc->device_guid, &dsoundsrc->pDSC, NULL); if (FAILED (hRes)) { goto capture_object; } gst_directsound_src_mixer_init (dsoundsrc); return TRUE; capture_function: { FreeLibrary (dsoundsrc->DSoundDLL); GST_ELEMENT_ERROR (dsoundsrc, RESOURCE, OPEN_READ, ("Unable to get capturecreate function"), (NULL)); return FALSE; } capture_enumerate: { FreeLibrary (dsoundsrc->DSoundDLL); GST_ELEMENT_ERROR (dsoundsrc, RESOURCE, OPEN_READ, ("Unable to enumerate audio capture devices"), (NULL)); return FALSE; } capture_object: { FreeLibrary (dsoundsrc->DSoundDLL); GST_ELEMENT_ERROR (dsoundsrc, RESOURCE, OPEN_READ, ("Unable to create capture object"), (NULL)); return FALSE; } dsound_open: { DWORD err = GetLastError (); GST_ELEMENT_ERROR (dsoundsrc, RESOURCE, OPEN_READ, ("Unable to open dsound.dll"), (NULL)); g_print ("0x%lx\n", HRESULT_FROM_WIN32 (err)); return FALSE; } }
static gboolean gst_directsound_src_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec) { GstDirectSoundSrc *dsoundsrc; WAVEFORMATEX wfx; /* Wave format structure */ HRESULT hRes; /* Result for windows functions */ DSCBUFFERDESC descSecondary; /* Capturebuffer description */ dsoundsrc = GST_DIRECTSOUND_SRC (asrc); GST_DEBUG_OBJECT (asrc, "preparing directsoundsrc"); /* Define buffer */ memset (&wfx, 0, sizeof (WAVEFORMATEX)); wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nChannels = GST_AUDIO_INFO_CHANNELS (&spec->info); wfx.nSamplesPerSec = GST_AUDIO_INFO_RATE (&spec->info); wfx.wBitsPerSample = GST_AUDIO_INFO_BPF (&spec->info) * 8 / wfx.nChannels; wfx.nBlockAlign = GST_AUDIO_INFO_BPF (&spec->info); wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; /* Ignored for WAVE_FORMAT_PCM. */ wfx.cbSize = 0; if (wfx.wBitsPerSample != 16 && wfx.wBitsPerSample != 8) goto dodgy_width; GST_INFO_OBJECT (asrc, "latency time: %" G_GUINT64_FORMAT " - buffer time: %" G_GUINT64_FORMAT, spec->latency_time, spec->buffer_time); /* Buffer-time should always be >= 2*latency */ if (spec->buffer_time < spec->latency_time * 2) { spec->buffer_time = spec->latency_time * 2; GST_WARNING ("buffer-time was less than 2*latency-time, clamping"); } /* Set the buffer size from our configured buffer time (in microsecs) */ dsoundsrc->buffer_size = gst_util_uint64_scale_int (spec->buffer_time, wfx.nAvgBytesPerSec, GST_SECOND / GST_USECOND); GST_INFO_OBJECT (asrc, "Buffer size: %d", dsoundsrc->buffer_size); spec->segsize = gst_util_uint64_scale (spec->latency_time, wfx.nAvgBytesPerSec, GST_SECOND / GST_USECOND); /* Sanitized segsize */ if (spec->segsize < GST_AUDIO_INFO_BPF (&spec->info)) spec->segsize = GST_AUDIO_INFO_BPF (&spec->info); else if (spec->segsize % GST_AUDIO_INFO_BPF (&spec->info) != 0) spec->segsize = ((spec->segsize + GST_AUDIO_INFO_BPF (&spec->info) - 1) / GST_AUDIO_INFO_BPF (&spec->info)) * GST_AUDIO_INFO_BPF (&spec->info); spec->segtotal = dsoundsrc->buffer_size / spec->segsize; /* The device usually takes time = 1-2 segments to start producing buffers */ spec->seglatency = spec->segtotal + 2; /* Fetch and set the actual latency time that will be used */ dsoundsrc->latency_time = gst_util_uint64_scale (spec->segsize, GST_SECOND / GST_USECOND, GST_AUDIO_INFO_BPF (&spec->info) * GST_AUDIO_INFO_RATE (&spec->info)); GST_INFO_OBJECT (asrc, "actual latency time: %" G_GUINT64_FORMAT, spec->latency_time); /* Init secondary buffer desciption */ memset (&descSecondary, 0, sizeof (DSCBUFFERDESC)); descSecondary.dwSize = sizeof (DSCBUFFERDESC); descSecondary.dwFlags = 0; descSecondary.dwReserved = 0; /* This is not primary buffer so have to set size */ descSecondary.dwBufferBytes = dsoundsrc->buffer_size; descSecondary.lpwfxFormat = &wfx; /* Create buffer */ hRes = IDirectSoundCapture_CreateCaptureBuffer (dsoundsrc->pDSC, &descSecondary, &dsoundsrc->pDSBSecondary, NULL); if (hRes != DS_OK) goto capture_buffer; dsoundsrc->bytes_per_sample = GST_AUDIO_INFO_BPF (&spec->info); GST_INFO_OBJECT (asrc, "bytes/sec: %lu, buffer size: %d, segsize: %d, segtotal: %d", wfx.nAvgBytesPerSec, dsoundsrc->buffer_size, spec->segsize, spec->segtotal); /* Not read anything yet */ dsoundsrc->current_circular_offset = 0; GST_INFO_OBJECT (asrc, "channels: %d, rate: %d, bytes_per_sample: %d" " WAVEFORMATEX.nSamplesPerSec: %ld, WAVEFORMATEX.wBitsPerSample: %d," " WAVEFORMATEX.nBlockAlign: %d, WAVEFORMATEX.nAvgBytesPerSec: %ld", GST_AUDIO_INFO_CHANNELS (&spec->info), GST_AUDIO_INFO_RATE (&spec->info), GST_AUDIO_INFO_BPF (&spec->info), wfx.nSamplesPerSec, wfx.wBitsPerSample, wfx.nBlockAlign, wfx.nAvgBytesPerSec); return TRUE; capture_buffer: { GST_ELEMENT_ERROR (dsoundsrc, RESOURCE, OPEN_READ, ("Unable to create capturebuffer"), (NULL)); return FALSE; } dodgy_width: { GST_ELEMENT_ERROR (dsoundsrc, RESOURCE, OPEN_READ, ("Unexpected width %d", wfx.wBitsPerSample), (NULL)); return FALSE; } }
static gboolean gst_directsound_src_event (GstBaseSrc * bsrc, GstEvent * event) { HRESULT hr; DWORD dwStatus; //DWORD dwSizeBuffer = 0; //LPVOID pLockedBuffer = NULL; GstDirectSoundSrc * dsoundsrc; dsoundsrc = GST_DIRECTSOUND_SRC (bsrc); GST_BASE_SRC_CLASS (parent_class)->event (bsrc, event); /* no buffer, no event to process */ if (!dsoundsrc->dsoundbuffer) return TRUE; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_START: GST_DSOUND_LOCK (dsoundsrc->dsoundbuffer); dsoundsrc->dsoundbuffer->flushing = TRUE; GST_DSOUND_UNLOCK (dsoundsrc->dsoundbuffer); break; case GST_EVENT_FLUSH_STOP: GST_DSOUND_LOCK (dsoundsrc->dsoundbuffer); dsoundsrc->dsoundbuffer->flushing = FALSE; if (dsoundsrc->dsoundbuffer->pDSCB8) { hr = IDirectSoundCaptureBuffer8_GetStatus (dsoundsrc->dsoundbuffer->pDSCB8, &dwStatus); if (FAILED(hr)) { GST_DSOUND_UNLOCK (dsoundsrc->dsoundbuffer); GST_WARNING("gst_directsound_src_event: IDirectSoundCaptureBuffer8_GetStatus, hr = %X", (unsigned int) hr); return FALSE; } if (!(dwStatus & DSCBSTATUS_CAPTURING)) { // ###: capture api doesn't support _SetCurrentPosition. commenting // out for now. #if 0 /* reset position */ hr = IDirectSoundBuffer8_SetCurrentPosition (dsoundsink->dsoundbuffer->pDSB8, 0); dsoundsink->dsoundbuffer->buffer_circular_offset = 0; /* reset the buffer */ hr = IDirectSoundBuffer8_Lock (dsoundsink->dsoundbuffer->pDSB8, dsoundsink->dsoundbuffer->buffer_circular_offset, 0L, &pLockedBuffer, &dwSizeBuffer, NULL, NULL, DSBLOCK_ENTIREBUFFER); if (SUCCEEDED (hr)) { memset (pLockedBuffer, 0, dwSizeBuffer); hr = IDirectSoundBuffer8_Unlock (dsoundsink->dsoundbuffer->pDSB8, pLockedBuffer, dwSizeBuffer, NULL, 0); if (FAILED(hr)) { GST_DSOUND_UNLOCK (dsoundsink->dsoundbuffer); GST_WARNING("gst_directsound_sink_event: IDirectSoundBuffer8_Unlock, hr = %X", (unsigned int) hr); return FALSE; } } else { GST_DSOUND_UNLOCK (dsoundsink->dsoundbuffer); GST_WARNING ( "gst_directsound_sink_event: IDirectSoundBuffer8_Lock, hr = %X", (unsigned int) hr); return FALSE; } #endif } } GST_DSOUND_UNLOCK (dsoundsrc->dsoundbuffer); break; default: break; } return TRUE; }