* even if the old device was unplugged. We need to handle this somehow.
* For example, perhaps we should automatically switch to the new device if
* the default device is changed and a device isn't explicitly selected. */
- if (!gst_wasapi_util_get_device_client (GST_ELEMENT (self), FALSE,
+ if (!gst_wasapi_util_get_device_client (GST_ELEMENT (self), eRender,
self->role, self->device_strid, &device, &client)) {
if (!self->device_strid)
GST_ELEMENT_ERROR (self, RESOURCE, OPEN_WRITE, (NULL),
if (gst_wasapi_sink_can_audioclient3 (self)) {
if (!gst_wasapi_util_initialize_audioclient3 (GST_ELEMENT (self), spec,
(IAudioClient3 *) self->client, self->mix_format, self->low_latency,
- &devicep_frames))
+ FALSE, &devicep_frames))
goto beach;
} else {
if (!gst_wasapi_util_initialize_audioclient (GST_ELEMENT (self), spec,
self->client, self->mix_format, self->sharemode, self->low_latency,
- &devicep_frames))
+ FALSE, &devicep_frames))
goto beach;
}
GST_STATIC_CAPS (GST_WASAPI_STATIC_CAPS));
#define DEFAULT_ROLE GST_WASAPI_DEVICE_ROLE_CONSOLE
+#define DEFAULT_LOOPBACK FALSE
#define DEFAULT_EXCLUSIVE FALSE
#define DEFAULT_LOW_LATENCY FALSE
#define DEFAULT_AUDIOCLIENT3 FALSE
PROP_0,
PROP_ROLE,
PROP_DEVICE,
+ PROP_LOOPBACK,
PROP_EXCLUSIVE,
PROP_LOW_LATENCY,
PROP_AUDIOCLIENT3
NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
+ PROP_LOOPBACK,
+ g_param_spec_boolean ("loopback", "Loopback recording",
+ "Open the sink device for loopback recording",
+ DEFAULT_LOOPBACK, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class,
PROP_EXCLUSIVE,
g_param_spec_boolean ("exclusive", "Exclusive mode",
"Open the device in exclusive mode",
self->role = DEFAULT_ROLE;
self->sharemode = AUDCLNT_SHAREMODE_SHARED;
+ self->loopback = DEFAULT_LOOPBACK;
self->low_latency = DEFAULT_LOW_LATENCY;
self->try_audioclient3 = DEFAULT_AUDIOCLIENT3;
self->event_handle = CreateEvent (NULL, FALSE, FALSE, NULL);
device ? g_utf8_to_utf16 (device, -1, NULL, NULL, NULL) : NULL;
break;
}
+ case PROP_LOOPBACK:
+ self->loopback = g_value_get_boolean (value);
+ break;
case PROP_EXCLUSIVE:
self->sharemode = g_value_get_boolean (value)
? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED;
g_value_take_string (value, self->device_strid ?
g_utf16_to_utf8 (self->device_strid, -1, NULL, NULL, NULL) : NULL);
break;
+ case PROP_LOOPBACK:
+ g_value_set_boolean (value, self->loopback);
+ break;
case PROP_EXCLUSIVE:
g_value_set_boolean (value,
self->sharemode == AUDCLNT_SHAREMODE_EXCLUSIVE);
* even if the old device was unplugged. We need to handle this somehow.
* For example, perhaps we should automatically switch to the new device if
* the default device is changed and a device isn't explicitly selected. */
- if (!gst_wasapi_util_get_device_client (GST_ELEMENT (self), TRUE,
- self->role, self->device_strid, &device, &client)) {
+ if (!gst_wasapi_util_get_device_client (GST_ELEMENT (self),
+ self->loopback ? eRender : eCapture, self->role, self->device_strid,
+ &device, &client)) {
if (!self->device_strid)
GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ, (NULL),
("Failed to get default device"));
if (gst_wasapi_src_can_audioclient3 (self)) {
if (!gst_wasapi_util_initialize_audioclient3 (GST_ELEMENT (self), spec,
(IAudioClient3 *) self->client, self->mix_format, self->low_latency,
- &devicep_frames))
+ self->loopback, &devicep_frames))
goto beach;
} else {
if (!gst_wasapi_util_initialize_audioclient (GST_ELEMENT (self), spec,
self->client, self->mix_format, self->sharemode, self->low_latency,
- &devicep_frames))
+ self->loopback, &devicep_frames))
goto beach;
}
/* properties */
gint role;
gint sharemode;
+ gboolean loopback;
gboolean low_latency;
gboolean try_audioclient3;
wchar_t *device_strid;
gboolean
gst_wasapi_util_get_device_client (GstElement * self,
- gboolean capture, gint role, const wchar_t * device_strid,
+ gint data_flow, gint role, const wchar_t * device_strid,
IMMDevice ** ret_device, IAudioClient ** ret_client)
{
gboolean res = FALSE;
goto beach;
if (!device_strid) {
- hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint (enumerator,
- capture ? eCapture : eRender, role, &device);
+ hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint (enumerator, data_flow,
+ role, &device);
HR_FAILED_GOTO (hr, IMMDeviceEnumerator::GetDefaultAudioEndpoint, beach);
} else {
hr = IMMDeviceEnumerator_GetDevice (enumerator, device_strid, &device);
gst_wasapi_util_initialize_audioclient (GstElement * self,
GstAudioRingBufferSpec * spec, IAudioClient * client,
WAVEFORMATEX * format, guint sharemode, gboolean low_latency,
- guint * ret_devicep_frames)
+ gboolean loopback, guint * ret_devicep_frames)
{
REFERENCE_TIME default_period, min_period;
REFERENCE_TIME device_period, device_buffer_duration;
- guint rate;
+ guint rate, stream_flags;
HRESULT hr;
hr = IAudioClient_GetDevicePeriod (client, &default_period, &min_period);
if (sharemode == AUDCLNT_SHAREMODE_EXCLUSIVE)
CoInitialize (NULL);
- hr = IAudioClient_Initialize (client, sharemode,
- AUDCLNT_STREAMFLAGS_EVENTCALLBACK, device_buffer_duration,
+ stream_flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
+ if (loopback)
+ stream_flags |= AUDCLNT_STREAMFLAGS_LOOPBACK;
+
+ hr = IAudioClient_Initialize (client, sharemode, stream_flags,
+ device_buffer_duration,
/* This must always be 0 in shared mode */
sharemode == AUDCLNT_SHAREMODE_SHARED ? 0 : device_period, format, NULL);
GST_WARNING_OBJECT (self, "trying to re-initialize with period %i "
"(%i frames, %i rate)", (int) device_period, n_frames, rate);
- hr = IAudioClient_Initialize (client, sharemode,
- AUDCLNT_STREAMFLAGS_EVENTCALLBACK, device_period,
- device_period, format, NULL);
+ hr = IAudioClient_Initialize (client, sharemode, stream_flags,
+ device_period, device_period, format, NULL);
}
HR_FAILED_RET (hr, IAudioClient::Initialize, FALSE);
gboolean
gst_wasapi_util_initialize_audioclient3 (GstElement * self,
GstAudioRingBufferSpec * spec, IAudioClient3 * client,
- WAVEFORMATEX * format, gboolean low_latency, guint * ret_devicep_frames)
+ WAVEFORMATEX * format, gboolean low_latency, gboolean loopback,
+ guint * ret_devicep_frames)
{
HRESULT hr;
+ gint stream_flags;
guint rate, devicep_frames;
guint defaultp_frames, fundp_frames, minp_frames, maxp_frames;
WAVEFORMATEX *tmpf;
devicep_frames = tmp * fundp_frames;
}
- hr = IAudioClient3_InitializeSharedAudioStream (client,
- AUDCLNT_STREAMFLAGS_EVENTCALLBACK, devicep_frames, format, NULL);
+ stream_flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
+ if (loopback)
+ stream_flags |= AUDCLNT_STREAMFLAGS_LOOPBACK;
+
+ hr = IAudioClient3_InitializeSharedAudioStream (client, stream_flags,
+ devicep_frames, format, NULL);
HR_FAILED_RET (hr, IAudioClient3::InitializeSharedAudioStream, FALSE);
hr = IAudioClient3_GetCurrentSharedModeEnginePeriod (client, &tmpf,
GList ** devices);
gboolean gst_wasapi_util_get_device_client (GstElement * element,
- gboolean capture, gint role, const wchar_t * device_strid,
+ gint data_flow, gint role, const wchar_t * device_strid,
IMMDevice ** ret_device, IAudioClient ** ret_client);
gboolean gst_wasapi_util_get_device_format (GstElement * element,
gboolean gst_wasapi_util_initialize_audioclient (GstElement * element,
GstAudioRingBufferSpec * spec, IAudioClient * client,
WAVEFORMATEX * format, guint sharemode, gboolean low_latency,
- guint * ret_devicep_frames);
+ gboolean loopback, guint * ret_devicep_frames);
gboolean gst_wasapi_util_initialize_audioclient3 (GstElement * element,
GstAudioRingBufferSpec * spec, IAudioClient3 * client,
- WAVEFORMATEX * format, gboolean low_latency, guint * ret_devicep_frames);
+ WAVEFORMATEX * format, gboolean low_latency, gboolean loopback,
+ guint * ret_devicep_frames);
HANDLE gst_wasapi_util_set_thread_characteristics (void);