mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 03:31:05 +00:00
osxaudio: Add some device provider properties
Add is-default and unique-id properties to the device provider. unique-id is particularly useful for recognising the device again as it's stable for a device across reboots and replugs. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5274>
This commit is contained in:
parent
e76581fe93
commit
81e3f7b4a4
4 changed files with 94 additions and 24 deletions
|
@ -93,7 +93,7 @@ gst_osx_audio_device_provider_init (GstOsxAudioDeviceProvider * provider)
|
||||||
static GstOsxAudioDevice *
|
static GstOsxAudioDevice *
|
||||||
gst_osx_audio_device_provider_probe_device (GstOsxAudioDeviceProvider *
|
gst_osx_audio_device_provider_probe_device (GstOsxAudioDeviceProvider *
|
||||||
provider, AudioDeviceID device_id, const gchar * device_name,
|
provider, AudioDeviceID device_id, const gchar * device_name,
|
||||||
GstOsxAudioDeviceType type)
|
GstOsxAudioDeviceType type, gboolean is_default)
|
||||||
{
|
{
|
||||||
GstOsxAudioDevice *device = NULL;
|
GstOsxAudioDevice *device = NULL;
|
||||||
GstCoreAudio *core_audio;
|
GstCoreAudio *core_audio;
|
||||||
|
@ -101,6 +101,7 @@ gst_osx_audio_device_provider_probe_device (GstOsxAudioDeviceProvider *
|
||||||
core_audio = gst_core_audio_new (NULL);
|
core_audio = gst_core_audio_new (NULL);
|
||||||
core_audio->is_src = type == GST_OSX_AUDIO_DEVICE_TYPE_SOURCE ? TRUE : FALSE;
|
core_audio->is_src = type == GST_OSX_AUDIO_DEVICE_TYPE_SOURCE ? TRUE : FALSE;
|
||||||
core_audio->device_id = device_id;
|
core_audio->device_id = device_id;
|
||||||
|
core_audio->is_default = is_default;
|
||||||
|
|
||||||
if (!gst_core_audio_open (core_audio)) {
|
if (!gst_core_audio_open (core_audio)) {
|
||||||
GST_ERROR ("CoreAudio device could not be opened");
|
GST_ERROR ("CoreAudio device could not be opened");
|
||||||
|
@ -118,42 +119,66 @@ done:
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline gchar *
|
static inline gchar *
|
||||||
_audio_device_get_name (AudioDeviceID device_id, gboolean output)
|
_audio_device_get_cfstring_prop (AudioDeviceID device_id, gboolean output,
|
||||||
|
AudioObjectPropertyElement prop_id)
|
||||||
{
|
{
|
||||||
OSStatus status = noErr;
|
OSStatus status = noErr;
|
||||||
UInt32 propertySize = 0;
|
UInt32 propertySize = 0;
|
||||||
gchar *device_name = NULL;
|
CFStringRef prop_val;
|
||||||
AudioObjectPropertyScope prop_scope;
|
gchar *result = NULL;
|
||||||
|
|
||||||
AudioObjectPropertyAddress deviceNameAddress = {
|
AudioObjectPropertyAddress propAddress = {
|
||||||
kAudioDevicePropertyDeviceName,
|
prop_id,
|
||||||
kAudioDevicePropertyScopeOutput,
|
kAudioDevicePropertyScopeOutput,
|
||||||
kAudioObjectPropertyElementMain
|
kAudioObjectPropertyElementMain
|
||||||
};
|
};
|
||||||
|
|
||||||
prop_scope = output ? kAudioDevicePropertyScopeOutput :
|
propAddress.mScope = output ? kAudioDevicePropertyScopeOutput :
|
||||||
kAudioDevicePropertyScopeInput;
|
kAudioDevicePropertyScopeInput;
|
||||||
|
|
||||||
deviceNameAddress.mScope = prop_scope;
|
|
||||||
|
|
||||||
/* Get the length of the device name */
|
/* Get the length of the device name */
|
||||||
status = AudioObjectGetPropertyDataSize (device_id,
|
status = AudioObjectGetPropertyDataSize (device_id,
|
||||||
&deviceNameAddress, 0, NULL, &propertySize);
|
&propAddress, 0, NULL, &propertySize);
|
||||||
if (status != noErr) {
|
if (status != noErr) {
|
||||||
goto beach;
|
goto beach;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the name of the device */
|
/* Get the requested property */
|
||||||
device_name = (gchar *) g_malloc (propertySize);
|
|
||||||
status = AudioObjectGetPropertyData (device_id,
|
status = AudioObjectGetPropertyData (device_id,
|
||||||
&deviceNameAddress, 0, NULL, &propertySize, device_name);
|
&propAddress, 0, NULL, &propertySize, &prop_val);
|
||||||
if (status != noErr) {
|
if (status != noErr) {
|
||||||
g_free (device_name);
|
goto beach;
|
||||||
device_name = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convert to UTF-8 C String */
|
||||||
|
CFIndex prop_len = CFStringGetLength (prop_val);
|
||||||
|
CFIndex max_size =
|
||||||
|
CFStringGetMaximumSizeForEncoding (prop_len, kCFStringEncodingUTF8) + 1;
|
||||||
|
result = g_malloc (max_size);
|
||||||
|
|
||||||
|
if (!CFStringGetCString (prop_val, result, max_size, kCFStringEncodingUTF8)) {
|
||||||
|
g_free (result);
|
||||||
|
result = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease (prop_val);
|
||||||
|
|
||||||
beach:
|
beach:
|
||||||
return device_name;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline gchar *
|
||||||
|
_audio_device_get_name (AudioDeviceID device_id, gboolean output)
|
||||||
|
{
|
||||||
|
return _audio_device_get_cfstring_prop (device_id, output,
|
||||||
|
kAudioObjectPropertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline gchar *
|
||||||
|
_audio_device_get_uid (AudioDeviceID device_id, gboolean output)
|
||||||
|
{
|
||||||
|
return _audio_device_get_cfstring_prop (device_id, output,
|
||||||
|
kAudioDevicePropertyDeviceUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline gboolean
|
static inline gboolean
|
||||||
|
@ -210,6 +235,35 @@ _audio_device_has_input (AudioDeviceID device_id)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline AudioDeviceID
|
||||||
|
_audio_system_get_default_device (gboolean output)
|
||||||
|
{
|
||||||
|
OSStatus status = noErr;
|
||||||
|
UInt32 propertySize = sizeof (AudioDeviceID);
|
||||||
|
AudioDeviceID device_id = kAudioDeviceUnknown;
|
||||||
|
AudioObjectPropertySelector prop_selector;
|
||||||
|
|
||||||
|
prop_selector = output ? kAudioHardwarePropertyDefaultOutputDevice :
|
||||||
|
kAudioHardwarePropertyDefaultInputDevice;
|
||||||
|
|
||||||
|
AudioObjectPropertyAddress defaultDeviceAddress = {
|
||||||
|
prop_selector,
|
||||||
|
kAudioObjectPropertyScopeGlobal,
|
||||||
|
kAudioObjectPropertyElementMain
|
||||||
|
};
|
||||||
|
|
||||||
|
status = AudioObjectGetPropertyData (kAudioObjectSystemObject,
|
||||||
|
&defaultDeviceAddress, 0, NULL, &propertySize, &device_id);
|
||||||
|
if (status != noErr) {
|
||||||
|
GST_ERROR ("failed getting default output device: %d", (int) status);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_DEBUG ("Default device id: %u", (unsigned) device_id);
|
||||||
|
|
||||||
|
return device_id;
|
||||||
|
}
|
||||||
|
|
||||||
static inline AudioDeviceID *
|
static inline AudioDeviceID *
|
||||||
_audio_system_get_devices (gint * ndevices)
|
_audio_system_get_devices (gint * ndevices)
|
||||||
{
|
{
|
||||||
|
@ -320,12 +374,15 @@ gst_osx_audio_device_provider_probe_internal (GstOsxAudioDeviceProvider * self,
|
||||||
type = GST_OSX_AUDIO_DEVICE_TYPE_SINK;
|
type = GST_OSX_AUDIO_DEVICE_TYPE_SINK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudioDeviceID default_device = _audio_system_get_default_device (!is_src);
|
||||||
|
|
||||||
for (i = 0; i < ndevices; i++) {
|
for (i = 0; i < ndevices; i++) {
|
||||||
gchar *device_name;
|
gchar *device_name;
|
||||||
|
|
||||||
if ((device_name = _audio_device_get_name (osx_devices[i], FALSE))) {
|
if ((device_name = _audio_device_get_name (osx_devices[i], FALSE))) {
|
||||||
gboolean has_output = _audio_device_has_output (osx_devices[i]);
|
gboolean has_output = _audio_device_has_output (osx_devices[i]);
|
||||||
gboolean has_input = _audio_device_has_input (osx_devices[i]);
|
gboolean has_input = _audio_device_has_input (osx_devices[i]);
|
||||||
|
gboolean is_default = (default_device == osx_devices[i]);
|
||||||
|
|
||||||
if (is_src && !has_input) {
|
if (is_src && !has_input) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
@ -335,7 +392,7 @@ gst_osx_audio_device_provider_probe_internal (GstOsxAudioDeviceProvider * self,
|
||||||
|
|
||||||
device =
|
device =
|
||||||
gst_osx_audio_device_provider_probe_device (self, osx_devices[i],
|
gst_osx_audio_device_provider_probe_device (self, osx_devices[i],
|
||||||
device_name, type);
|
device_name, type, is_default);
|
||||||
if (device) {
|
if (device) {
|
||||||
if (is_src) {
|
if (is_src) {
|
||||||
GST_DEBUG ("Input Device ID: %u Name: %s",
|
GST_DEBUG ("Input Device ID: %u Name: %s",
|
||||||
|
@ -553,10 +610,20 @@ gst_osx_audio_device_new (AudioDeviceID device_id, const gchar * device_name,
|
||||||
const gchar *element_name = NULL;
|
const gchar *element_name = NULL;
|
||||||
const gchar *klass = NULL;
|
const gchar *klass = NULL;
|
||||||
GstCaps *template_caps, *caps;
|
GstCaps *template_caps, *caps;
|
||||||
|
GstStructure *props = gst_structure_new_empty ("properties");
|
||||||
|
|
||||||
g_return_val_if_fail (device_id > 0, NULL);
|
g_return_val_if_fail (device_id > 0, NULL);
|
||||||
g_return_val_if_fail (device_name, NULL);
|
g_return_val_if_fail (device_name, NULL);
|
||||||
|
|
||||||
|
gst_structure_set (props, "is-default", G_TYPE_BOOLEAN,
|
||||||
|
core_audio->is_default, NULL);
|
||||||
|
|
||||||
|
gchar *uid = _audio_device_get_uid (device_id, !core_audio->is_src);
|
||||||
|
if (uid != NULL) {
|
||||||
|
gst_structure_set (props, "unique-id", G_TYPE_STRING, uid, NULL);
|
||||||
|
g_free (uid);
|
||||||
|
}
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case GST_OSX_AUDIO_DEVICE_TYPE_SOURCE:
|
case GST_OSX_AUDIO_DEVICE_TYPE_SOURCE:
|
||||||
element_name = "osxaudiosrc";
|
element_name = "osxaudiosrc";
|
||||||
|
@ -582,8 +649,8 @@ gst_osx_audio_device_new (AudioDeviceID device_id, const gchar * device_name,
|
||||||
}
|
}
|
||||||
|
|
||||||
gstdev = g_object_new (GST_TYPE_OSX_AUDIO_DEVICE, "device-id",
|
gstdev = g_object_new (GST_TYPE_OSX_AUDIO_DEVICE, "device-id",
|
||||||
device_id, "display-name", device_name, "caps", caps, "device-class",
|
device_id, "display-name", device_name, "caps", caps,
|
||||||
klass, NULL);
|
"properties", props, "device-class", klass, NULL);
|
||||||
|
|
||||||
gstdev->element = element_name;
|
gstdev->element = element_name;
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,7 @@ struct _GstCoreAudio
|
||||||
gboolean is_src;
|
gboolean is_src;
|
||||||
gboolean is_passthrough;
|
gboolean is_passthrough;
|
||||||
AudioDeviceID device_id;
|
AudioDeviceID device_id;
|
||||||
|
gboolean is_default;
|
||||||
gboolean cached_caps_valid; /* thread-safe flag */
|
gboolean cached_caps_valid; /* thread-safe flag */
|
||||||
GstCaps *cached_caps;
|
GstCaps *cached_caps;
|
||||||
gint stream_idx;
|
gint stream_idx;
|
||||||
|
|
|
@ -1224,13 +1224,12 @@ gst_core_audio_select_device_impl (GstCoreAudio * core_audio)
|
||||||
gboolean output = !core_audio->is_src;
|
gboolean output = !core_audio->is_src;
|
||||||
gboolean res = FALSE;
|
gboolean res = FALSE;
|
||||||
|
|
||||||
|
/* Find the ID of the default output device */
|
||||||
|
AudioDeviceID default_device_id = _audio_system_get_default_device (output);
|
||||||
|
|
||||||
/* Here we decide if selected device is valid or autoselect
|
/* Here we decide if selected device is valid or autoselect
|
||||||
* the default one when required */
|
* the default one when required */
|
||||||
if (device_id == kAudioDeviceUnknown) {
|
if (device_id == kAudioDeviceUnknown) {
|
||||||
AudioDeviceID default_device_id;
|
|
||||||
|
|
||||||
/* Find the ID of the default output device */
|
|
||||||
default_device_id = _audio_system_get_default_device (output);
|
|
||||||
|
|
||||||
if (default_device_id != kAudioDeviceUnknown) {
|
if (default_device_id != kAudioDeviceUnknown) {
|
||||||
device_id = default_device_id;
|
device_id = default_device_id;
|
||||||
|
@ -1304,8 +1303,10 @@ gst_core_audio_select_device_impl (GstCoreAudio * core_audio)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res)
|
if (res) {
|
||||||
core_audio->device_id = device_id;
|
core_audio->device_id = device_id;
|
||||||
|
core_audio->is_default = (device_id == default_device_id);
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,6 +126,7 @@ static gboolean
|
||||||
gst_core_audio_select_device_impl (GstCoreAudio * core_audio)
|
gst_core_audio_select_device_impl (GstCoreAudio * core_audio)
|
||||||
{
|
{
|
||||||
/* No device selection in iOS */
|
/* No device selection in iOS */
|
||||||
|
core_audio->is_default = TRUE;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue