osxaudio: Work around invalid channel positions from CoreAudio

By default, for devices with larger amounts of outputs, CoreAudio can
provide invalid channel labels/positions, simply by starting at 0 and
incrementing forward. For example, values 19 through 32 are not valid
according to the CoreAudioBaseTypes.h header, but if your device has >19
output channels, you will find CoreAudio using those values.

This is most likely a bug in CoreAudio, since in that case it should use
unpositioned labels (e.g. _Discrete_X) instead.

This commit aims to work around this by overriding all channels to be
unpositioned if the case above is detected.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8311>
This commit is contained in:
Piotr Brzeziński 2025-01-16 17:27:50 +01:00 committed by GStreamer Marge Bot
parent 83e95af6e3
commit c5c5327df6

View file

@ -492,6 +492,29 @@ _is_core_audio_layout_positioned (AudioChannelLayout * layout)
return FALSE;
}
static gboolean
_core_audio_has_invalid_channel_labels (AudioChannelLayout * layout)
{
guint i;
g_assert (layout->mChannelLayoutTag ==
kAudioChannelLayoutTag_UseChannelDescriptions);
for (i = 0; i < layout->mNumberChannelDescriptions; ++i) {
/* Let's use our mapping to judge whether the value is valid.
* It doesn't support all of the defined positions, but the missing ones
* aren't useful to us anyway. */
GstAudioChannelPosition p =
gst_core_audio_channel_label_to_gst
(layout->mChannelDescriptions[i].mChannelLabel, i, FALSE);
if (p == GST_AUDIO_CHANNEL_POSITION_INVALID)
return TRUE;
}
return FALSE;
}
static void
_core_audio_parse_channel_descriptions (AudioChannelLayout * layout,
guint * channels, guint64 * channel_mask, GstAudioChannelPosition * pos)
@ -502,6 +525,24 @@ _core_audio_parse_channel_descriptions (AudioChannelLayout * layout,
g_assert (layout->mChannelLayoutTag ==
kAudioChannelLayoutTag_UseChannelDescriptions);
/* For >16ch devices, CoreAudio can give out completely incorrect
* channel positions by default - instead of using kAudioChannelLabel_Discrete_X,
* it just returns incrementing values starting from 0, some of which are not
* valid if you check against the CoreAudioBaseTypes.h header.
* If such case is detected, let's just swap all positions to Discrete,
* which map to GST_AUDIO_CHANNEL_POSITION_NONE. */
if (_core_audio_has_invalid_channel_labels (layout)) {
GST_DEBUG
("Invalid channel positions given by CoreAudio, setting all to unpositioned");
if (pos) {
for (i = 0; i < layout->mNumberChannelDescriptions; ++i)
pos[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
}
*channels = layout->mNumberChannelDescriptions;
*channel_mask = 0;
return;
}
positioned = _is_core_audio_layout_positioned (layout);
*channel_mask = 0;