wasapi2: Probe exclusive mode formats
... and report it via device provider props Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/9586>
This commit is contained in:
parent
34a009d85c
commit
370499875c
@ -257,6 +257,11 @@ gst_wasapi2_device_provider_probe (GstDeviceProvider * provider)
|
||||
gst_structure_set (props,
|
||||
"wasapi2.device.loopback", G_TYPE_BOOLEAN, FALSE, nullptr);
|
||||
|
||||
if (!entry->is_default && entry->exclusive_caps) {
|
||||
gst_structure_set (props, "device.exclusive-caps", GST_TYPE_CAPS,
|
||||
entry->exclusive_caps, nullptr);
|
||||
}
|
||||
|
||||
auto device = (GstDevice *) g_object_new (GST_TYPE_WASAPI2_DEVICE,
|
||||
"device", entry->device_id.c_str (),
|
||||
"display-name", entry->device_name.c_str (), "caps", entry->caps,
|
||||
@ -274,6 +279,11 @@ gst_wasapi2_device_provider_probe (GstDeviceProvider * provider)
|
||||
gst_structure_set (prop_copy,
|
||||
"wasapi2.device.loopback", G_TYPE_BOOLEAN, TRUE, nullptr);
|
||||
|
||||
if (!entry->is_default && entry->exclusive_caps) {
|
||||
gst_structure_set (props, "device.exclusive-caps", GST_TYPE_CAPS,
|
||||
entry->exclusive_caps, nullptr);
|
||||
}
|
||||
|
||||
auto device = (GstDevice *) g_object_new (GST_TYPE_WASAPI2_DEVICE,
|
||||
"device", entry->device_id.c_str (),
|
||||
"display-name", entry->device_name.c_str (), "caps", entry->caps,
|
||||
|
@ -48,8 +48,6 @@ ensure_debug_category (void)
|
||||
}
|
||||
#endif
|
||||
|
||||
static GstStaticCaps template_caps = GST_STATIC_CAPS (GST_WASAPI2_STATIC_CAPS);
|
||||
|
||||
static void gst_wasapi2_on_device_updated (GstWasapi2Enumerator * object);
|
||||
|
||||
static std::string
|
||||
@ -263,13 +261,14 @@ struct GstWasapi2EnumeratorPrivate
|
||||
{
|
||||
device_list = g_ptr_array_new_with_free_func ((GDestroyNotify)
|
||||
gst_wasapi2_enumerator_entry_free);
|
||||
scaps = gst_static_caps_get (&template_caps);
|
||||
exclusive_formats = g_ptr_array_new_with_free_func ((GDestroyNotify)
|
||||
gst_wasapi2_free_wfx);
|
||||
}
|
||||
|
||||
~GstWasapi2EnumeratorPrivate ()
|
||||
{
|
||||
g_ptr_array_unref (device_list);
|
||||
gst_caps_unref (scaps);
|
||||
g_ptr_array_unref (exclusive_formats);
|
||||
}
|
||||
|
||||
ComPtr<IMMDeviceEnumerator> handle;
|
||||
@ -281,7 +280,7 @@ struct GstWasapi2EnumeratorPrivate
|
||||
Wasapi2ActivationHandler *render_activator = nullptr;
|
||||
std::atomic<int> notify_count = { 0 };
|
||||
GPtrArray *device_list;
|
||||
GstCaps *scaps;
|
||||
GPtrArray *exclusive_formats;
|
||||
|
||||
void ClearCOM ()
|
||||
{
|
||||
@ -556,13 +555,12 @@ struct EnumerateData
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
static void
|
||||
gst_wasapi2_enumerator_add_entry (GstWasapi2Enumerator * self,
|
||||
IAudioClient * client,
|
||||
GstCaps * static_caps, EDataFlow flow, gboolean is_default,
|
||||
static GstWasapi2EnumeratorEntry *
|
||||
gst_wasapi2_enumerator_build_entry (GstWasapi2Enumerator * self,
|
||||
IAudioClient * client, EDataFlow flow, gboolean is_default,
|
||||
gchar * device_id, gchar * device_name,
|
||||
gchar * actual_device_id, gchar * actual_device_name,
|
||||
GstWasapi2DeviceProps * device_props, GPtrArray * device_list)
|
||||
GstWasapi2DeviceProps * device_props)
|
||||
{
|
||||
WAVEFORMATEX *mix_format = nullptr;
|
||||
GstCaps *supported_caps = nullptr;
|
||||
@ -573,11 +571,10 @@ gst_wasapi2_enumerator_add_entry (GstWasapi2Enumerator * self,
|
||||
g_free (device_name);
|
||||
g_free (actual_device_id);
|
||||
g_free (actual_device_name);
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gst_wasapi2_util_parse_waveformatex (mix_format,
|
||||
static_caps, &supported_caps, nullptr);
|
||||
gst_wasapi2_util_parse_waveformatex (mix_format, &supported_caps, nullptr);
|
||||
CoTaskMemFree (mix_format);
|
||||
|
||||
if (!supported_caps) {
|
||||
@ -585,7 +582,7 @@ gst_wasapi2_enumerator_add_entry (GstWasapi2Enumerator * self,
|
||||
g_free (device_name);
|
||||
g_free (actual_device_id);
|
||||
g_free (actual_device_name);
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto entry = new GstWasapi2EnumeratorEntry ();
|
||||
@ -612,7 +609,7 @@ gst_wasapi2_enumerator_add_entry (GstWasapi2Enumerator * self,
|
||||
g_free (actual_device_id);
|
||||
g_free (actual_device_name);
|
||||
|
||||
g_ptr_array_add (device_list, entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -739,12 +736,15 @@ gst_wasapi2_enumerator_execute (GstWasapi2Enumerator * self,
|
||||
if (default_capture_prop)
|
||||
gst_wasapi2_enumerator_probe_props (default_capture_prop.Get (), &props);
|
||||
|
||||
gst_wasapi2_enumerator_add_entry (self, default_capture_client.Get (),
|
||||
priv->scaps, eCapture, TRUE,
|
||||
auto entry = gst_wasapi2_enumerator_build_entry (self,
|
||||
default_capture_client.Get (), eCapture, TRUE,
|
||||
g_strdup (gst_wasapi2_get_default_device_id (eCapture)),
|
||||
g_strdup ("Default Audio Capture Device"),
|
||||
g_strdup (default_capture_device_id),
|
||||
g_strdup (default_capture_device_name), &props, priv->device_list);
|
||||
g_strdup (default_capture_device_name), &props);
|
||||
|
||||
if (entry)
|
||||
g_ptr_array_add (priv->device_list, entry);
|
||||
}
|
||||
|
||||
if (default_render_client) {
|
||||
@ -755,12 +755,15 @@ gst_wasapi2_enumerator_execute (GstWasapi2Enumerator * self,
|
||||
if (default_render_prop)
|
||||
gst_wasapi2_enumerator_probe_props (default_render_prop.Get (), &props);
|
||||
|
||||
gst_wasapi2_enumerator_add_entry (self, default_render_client.Get (),
|
||||
priv->scaps, eRender, TRUE,
|
||||
auto entry = gst_wasapi2_enumerator_build_entry (self,
|
||||
default_render_client.Get (), eRender, TRUE,
|
||||
g_strdup (gst_wasapi2_get_default_device_id (eRender)),
|
||||
g_strdup ("Default Audio Render Device"),
|
||||
g_strdup (default_render_device_id),
|
||||
g_strdup (default_render_device_name), &props, priv->device_list);
|
||||
g_strdup (default_render_device_name), &props);
|
||||
|
||||
if (entry)
|
||||
g_ptr_array_add (priv->device_list, entry);
|
||||
}
|
||||
|
||||
for (UINT i = 0; i < count; i++) {
|
||||
@ -829,8 +832,19 @@ gst_wasapi2_enumerator_execute (GstWasapi2Enumerator * self,
|
||||
|
||||
gst_wasapi2_enumerator_probe_props (prop.Get (), &props);
|
||||
|
||||
gst_wasapi2_enumerator_add_entry (self, client.Get (), priv->scaps, flow,
|
||||
FALSE, device_id, desc, nullptr, nullptr, &props, priv->device_list);
|
||||
auto entry = gst_wasapi2_enumerator_build_entry (self, client.Get (), flow,
|
||||
FALSE, device_id, desc, nullptr, nullptr, &props);
|
||||
if (entry) {
|
||||
g_ptr_array_set_size (priv->exclusive_formats, 0);
|
||||
gst_wasapi2_get_exclusive_formats (client.Get (),
|
||||
prop.Get (), priv->exclusive_formats);
|
||||
auto exclusive_caps =
|
||||
gst_wasapi2_wfx_list_to_caps (priv->exclusive_formats);
|
||||
g_ptr_array_set_size (priv->exclusive_formats, 0);
|
||||
|
||||
entry->exclusive_caps = exclusive_caps;
|
||||
g_ptr_array_add (priv->device_list, entry);
|
||||
}
|
||||
}
|
||||
|
||||
g_free (default_capture_device_id);
|
||||
|
@ -42,6 +42,7 @@ struct GstWasapi2EnumeratorEntry
|
||||
~GstWasapi2EnumeratorEntry()
|
||||
{
|
||||
gst_clear_caps (&caps);
|
||||
gst_clear_caps (&exclusive_caps);
|
||||
}
|
||||
|
||||
std::string device_id;
|
||||
@ -50,6 +51,7 @@ struct GstWasapi2EnumeratorEntry
|
||||
std::string actual_device_name;
|
||||
gboolean is_default = FALSE;
|
||||
GstCaps *caps = nullptr;
|
||||
GstCaps *exclusive_caps = nullptr;
|
||||
EDataFlow flow;
|
||||
GstWasapi2DeviceProps device_props = { };
|
||||
};
|
||||
|
@ -76,8 +76,6 @@
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_wasapi2_rbuf_debug);
|
||||
#define GST_CAT_DEFAULT gst_wasapi2_rbuf_debug
|
||||
|
||||
static GstStaticCaps template_caps = GST_STATIC_CAPS (GST_WASAPI2_STATIC_CAPS);
|
||||
|
||||
/* Defined for _WIN32_WINNT >= _NT_TARGET_VERSION_WIN10_RS4 */
|
||||
#ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION
|
||||
#define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x00000002
|
||||
@ -710,15 +708,13 @@ gst_wasapi2_device_manager_create_ctx (IMMDeviceEnumerator * enumerator,
|
||||
return;
|
||||
}
|
||||
|
||||
auto scaps = gst_static_caps_get (&template_caps);
|
||||
GstCaps *old_caps = nullptr;
|
||||
GstCaps *new_caps = nullptr;
|
||||
|
||||
gst_wasapi2_util_parse_waveformatex (desc->mix_format,
|
||||
scaps, &old_caps, nullptr);
|
||||
&old_caps, nullptr);
|
||||
gst_wasapi2_util_parse_waveformatex (closest,
|
||||
scaps, &new_caps, nullptr);
|
||||
gst_caps_unref (scaps);
|
||||
&new_caps, nullptr);
|
||||
|
||||
if (!new_caps || !old_caps) {
|
||||
GST_ERROR ("Couldn't get caps from format");
|
||||
@ -750,10 +746,8 @@ gst_wasapi2_device_manager_create_ctx (IMMDeviceEnumerator * enumerator,
|
||||
}
|
||||
}
|
||||
|
||||
auto scaps = gst_static_caps_get (&template_caps);
|
||||
gst_wasapi2_util_parse_waveformatex (ctx->mix_format,
|
||||
scaps, &ctx->caps, nullptr);
|
||||
gst_caps_unref (scaps);
|
||||
&ctx->caps, nullptr);
|
||||
|
||||
hr = E_FAIL;
|
||||
/* Try IAudioClient3 if low-latency is requested */
|
||||
@ -2179,10 +2173,8 @@ gst_wasapi2_rbuf_loop_thread (GstWasapi2Rbuf * self)
|
||||
if (priv->configured_allow_dummy) {
|
||||
priv->mix_format = gst_wasapi2_get_default_mix_format ();
|
||||
|
||||
auto scaps = gst_static_caps_get (&template_caps);
|
||||
gst_wasapi2_util_parse_waveformatex (priv->mix_format,
|
||||
scaps, &priv->caps, nullptr);
|
||||
gst_caps_unref (scaps);
|
||||
&priv->caps, nullptr);
|
||||
priv->opened = true;
|
||||
|
||||
cmd->hr = S_OK;
|
||||
|
@ -29,10 +29,18 @@
|
||||
#include <winternl.h>
|
||||
#include <mutex>
|
||||
#include <string.h>
|
||||
#include <wrl.h>
|
||||
#include <vector>
|
||||
|
||||
GST_DEBUG_CATEGORY_EXTERN (gst_wasapi2_debug);
|
||||
#define GST_CAT_DEFAULT gst_wasapi2_debug
|
||||
|
||||
static GstStaticCaps template_caps = GST_STATIC_CAPS (GST_WASAPI2_STATIC_CAPS);
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
using namespace Microsoft::WRL;
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/* Define GUIDs instead of linking ksuser.lib */
|
||||
DEFINE_GUID (GST_KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010,
|
||||
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
|
||||
@ -412,8 +420,7 @@ gst_wasapi2_util_waveformatex_to_audio_format (WAVEFORMATEX * format)
|
||||
|
||||
gboolean
|
||||
gst_wasapi2_util_parse_waveformatex (WAVEFORMATEX * format,
|
||||
GstCaps * template_caps, GstCaps ** out_caps,
|
||||
GstAudioChannelPosition ** out_positions)
|
||||
GstCaps ** out_caps, GstAudioChannelPosition ** out_positions)
|
||||
{
|
||||
const gchar *afmt;
|
||||
guint64 channel_mask;
|
||||
@ -437,21 +444,24 @@ gst_wasapi2_util_parse_waveformatex (WAVEFORMATEX * format,
|
||||
if (afmt == NULL)
|
||||
return FALSE;
|
||||
|
||||
*out_caps = gst_caps_copy (template_caps);
|
||||
auto caps = gst_static_caps_get (&template_caps);
|
||||
caps = gst_caps_make_writable (caps);
|
||||
|
||||
channel_mask = gst_wasapi2_util_waveformatex_to_channel_mask (format,
|
||||
out_positions);
|
||||
|
||||
gst_caps_set_simple (*out_caps,
|
||||
gst_caps_set_simple (caps,
|
||||
"format", G_TYPE_STRING, afmt,
|
||||
"channels", G_TYPE_INT, format->nChannels,
|
||||
"rate", G_TYPE_INT, format->nSamplesPerSec, NULL);
|
||||
|
||||
if (channel_mask) {
|
||||
gst_caps_set_simple (*out_caps,
|
||||
gst_caps_set_simple (caps,
|
||||
"channel-mask", GST_TYPE_BITMASK, channel_mask, NULL);
|
||||
}
|
||||
|
||||
*out_caps = caps;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -634,3 +644,185 @@ gst_wasapi2_role_to_string (ERole role)
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
void
|
||||
gst_wasapi2_free_wfx (WAVEFORMATEX * wfx)
|
||||
{
|
||||
if (wfx)
|
||||
CoTaskMemFree (wfx);
|
||||
}
|
||||
|
||||
void
|
||||
gst_wasapi2_clear_wfx (WAVEFORMATEX ** wfx)
|
||||
{
|
||||
if (*wfx) {
|
||||
CoTaskMemFree (*wfx);
|
||||
*wfx = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
WAVEFORMATEX *
|
||||
gst_wasapi2_copy_wfx (WAVEFORMATEX * src)
|
||||
{
|
||||
guint total_size = sizeof (WAVEFORMATEX) + src->cbSize;
|
||||
auto dst = (WAVEFORMATEX *) CoTaskMemAlloc (total_size);
|
||||
memcpy (dst, src, total_size);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
static DWORD
|
||||
make_channel_mask (WORD nChannels)
|
||||
{
|
||||
switch (nChannels) {
|
||||
case 1:
|
||||
return KSAUDIO_SPEAKER_MONO;
|
||||
case 2:
|
||||
return KSAUDIO_SPEAKER_STEREO;
|
||||
case 4:
|
||||
return KSAUDIO_SPEAKER_3POINT1;
|
||||
case 6:
|
||||
return KSAUDIO_SPEAKER_5POINT1;
|
||||
case 8:
|
||||
return KSAUDIO_SPEAKER_7POINT1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static WAVEFORMATEXTENSIBLE
|
||||
make_wfx_ext (DWORD nSamplesPerSec, WORD nChannels, WORD wBitsPerSample,
|
||||
WORD wValidBitsPerSample, bool is_float)
|
||||
{
|
||||
WAVEFORMATEXTENSIBLE w = { };
|
||||
w.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
||||
w.Format.nChannels = nChannels;
|
||||
w.Format.nSamplesPerSec = nSamplesPerSec;
|
||||
|
||||
w.Format.wBitsPerSample = wBitsPerSample;
|
||||
w.Samples.wValidBitsPerSample = wValidBitsPerSample;
|
||||
|
||||
w.dwChannelMask = make_channel_mask (nChannels);
|
||||
w.SubFormat = is_float ? GST_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
|
||||
: GST_KSDATAFORMAT_SUBTYPE_PCM;
|
||||
|
||||
w.Format.nBlockAlign = (wBitsPerSample / 8) * nChannels;
|
||||
w.Format.nAvgBytesPerSec = w.Format.nSamplesPerSec * w.Format.nBlockAlign;
|
||||
w.Format.cbSize = sizeof (WAVEFORMATEXTENSIBLE) - sizeof (WAVEFORMATEX);
|
||||
|
||||
return w;
|
||||
}
|
||||
/* *INDENT-OFF* */
|
||||
gboolean
|
||||
gst_wasapi2_get_exclusive_formats (IAudioClient * client,
|
||||
IPropertyStore * props, GPtrArray * list)
|
||||
{
|
||||
PROPVARIANT var;
|
||||
PropVariantInit (&var);
|
||||
WAVEFORMATEX *device_format = nullptr;
|
||||
WAVEFORMATEX *closest = nullptr;
|
||||
|
||||
/* Prefer device format if supported */
|
||||
auto hr = props->GetValue (PKEY_AudioEngine_DeviceFormat, &var);
|
||||
if (gst_wasapi2_result (hr)) {
|
||||
if (var.vt == VT_BLOB && var.blob.cbSize >= sizeof (WAVEFORMATEX)
|
||||
&& var.blob.pBlobData) {
|
||||
device_format = (WAVEFORMATEX *) CoTaskMemAlloc (var.blob.cbSize);
|
||||
|
||||
memcpy (device_format, var.blob.pBlobData, var.blob.cbSize);
|
||||
}
|
||||
PropVariantClear (&var);
|
||||
}
|
||||
|
||||
if (device_format) {
|
||||
hr = client->IsFormatSupported (AUDCLNT_SHAREMODE_EXCLUSIVE, device_format,
|
||||
&closest);
|
||||
|
||||
if (hr == S_OK) {
|
||||
g_ptr_array_add (list, device_format);
|
||||
device_format = nullptr;
|
||||
} else if (hr == S_FALSE && closest) {
|
||||
g_ptr_array_add (list, closest);
|
||||
closest = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
gst_wasapi2_clear_wfx (&device_format);
|
||||
|
||||
/* Checks using pre-defined format list */
|
||||
struct DepthPair
|
||||
{
|
||||
WORD wBitsPerSample;
|
||||
WORD wValidBitsPerSample;
|
||||
bool is_float;
|
||||
};
|
||||
|
||||
const DepthPair depth_pairs[] = {
|
||||
{32, 32, true}, /* 32-float */
|
||||
{32, 32, false}, /* 32-int */
|
||||
{32, 24, false}, /* 24-in-32 */
|
||||
{24, 24, false}, /* 24-packed */
|
||||
{16, 16, false}, /* 16-int */
|
||||
};
|
||||
|
||||
const DWORD rates[] = { 192000, 176400, 96000, 88200, 48000, 44100 };
|
||||
const WORD chs[] = { 8, 6, 2, 1 };
|
||||
|
||||
for (auto r : rates) {
|
||||
for (auto c : chs) {
|
||||
for (auto d : depth_pairs) {
|
||||
auto wfx = make_wfx_ext (r, c, d.wBitsPerSample, d.wValidBitsPerSample,
|
||||
d.is_float);
|
||||
hr = client->IsFormatSupported (AUDCLNT_SHAREMODE_EXCLUSIVE,
|
||||
(WAVEFORMATEX *) &wfx, &closest);
|
||||
if (hr == S_OK) {
|
||||
g_ptr_array_add (list, gst_wasapi2_copy_wfx ((WAVEFORMATEX *) &wfx));
|
||||
} else if (hr == S_FALSE && closest) {
|
||||
g_ptr_array_add (list, closest);
|
||||
closest = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GstCaps *
|
||||
gst_wasapi2_wfx_list_to_caps (GPtrArray * list)
|
||||
{
|
||||
if (!list || list->len == 0)
|
||||
return nullptr;
|
||||
|
||||
std::vector <GstCaps *> caps_list;
|
||||
|
||||
for (guint i = 0; i < list->len; i++) {
|
||||
auto wfx = (WAVEFORMATEX *) g_ptr_array_index (list, i);
|
||||
GstCaps *tmp;
|
||||
|
||||
if (gst_wasapi2_util_parse_waveformatex (wfx, &tmp, nullptr)) {
|
||||
bool unique = true;
|
||||
for (auto it : caps_list) {
|
||||
if (gst_caps_is_equal (it, tmp)) {
|
||||
unique = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (unique)
|
||||
caps_list.push_back (tmp);
|
||||
else
|
||||
gst_caps_unref (tmp);
|
||||
}
|
||||
}
|
||||
|
||||
if (caps_list.empty ())
|
||||
return nullptr;
|
||||
|
||||
auto caps = gst_caps_new_empty ();
|
||||
for (auto it : caps_list)
|
||||
gst_caps_append (caps, it);
|
||||
|
||||
return caps;
|
||||
}
|
||||
/* *INDENT-ON* */
|
||||
|
@ -101,7 +101,6 @@ guint64 gst_wasapi2_util_waveformatex_to_channel_mask (WAVEFORMATEX * form
|
||||
const gchar * gst_wasapi2_util_waveformatex_to_audio_format (WAVEFORMATEX * format);
|
||||
|
||||
gboolean gst_wasapi2_util_parse_waveformatex (WAVEFORMATEX * format,
|
||||
GstCaps * template_caps,
|
||||
GstCaps ** out_caps,
|
||||
GstAudioChannelPosition ** out_positions);
|
||||
|
||||
@ -121,6 +120,18 @@ const gchar * gst_wasapi2_data_flow_to_string (EDataFlow flow);
|
||||
|
||||
const gchar * gst_wasapi2_role_to_string (ERole role);
|
||||
|
||||
void gst_wasapi2_free_wfx (WAVEFORMATEX * wfx);
|
||||
|
||||
void gst_wasapi2_clear_wfx (WAVEFORMATEX ** wfx);
|
||||
|
||||
WAVEFORMATEX * gst_wasapi2_copy_wfx (WAVEFORMATEX * format);
|
||||
|
||||
gboolean gst_wasapi2_get_exclusive_formats (IAudioClient * client,
|
||||
IPropertyStore * props,
|
||||
GPtrArray * list);
|
||||
|
||||
GstCaps * gst_wasapi2_wfx_list_to_caps (GPtrArray * list);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
Loading…
x
Reference in New Issue
Block a user