[vlc-commits] audiounit_ios: handle output channels layout
Thomas Guillem
git at videolan.org
Wed Mar 1 17:49:53 CET 2017
vlc | branch: master | Thomas Guillem <thomas at gllm.fr> | Fri Feb 24 18:35:04 2017 +0100| [806f65bfcfeae12f4b0edeb72ff59fc23a15ebb3] | committer: Thomas Guillem
audiounit_ios: handle output channels layout
Use AVAudioSession to get the maximum number of channels and set the preferred
number of channels regarding to this maximum.
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=806f65bfcfeae12f4b0edeb72ff59fc23a15ebb3
---
modules/audio_output/audiounit_ios.m | 126 +++++++++++++++++++++++++++++++++--
1 file changed, 122 insertions(+), 4 deletions(-)
diff --git a/modules/audio_output/audiounit_ios.m b/modules/audio_output/audiounit_ios.m
index 8f66257..7dc3720 100644
--- a/modules/audio_output/audiounit_ios.m
+++ b/modules/audio_output/audiounit_ios.m
@@ -25,6 +25,7 @@
#import "coreaudio_common.h"
#import <vlc_plugin.h>
+#import <vlc_memory.h>
#import <CoreAudio/CoreAudioTypes.h>
#import <Foundation/Foundation.h>
@@ -66,10 +67,115 @@ struct aout_sys_t
bool b_muted;
};
+enum dev_type {
+ DEV_TYPE_DEFAULT,
+ DEV_TYPE_USB,
+ DEV_TYPE_HDMI
+};
+
#pragma mark -
#pragma mark AVAudioSession route and output handling
static int
+avas_GetOptimalChannelLayout(audio_output_t *p_aout, unsigned channel_count,
+ enum dev_type *pdev_type,
+ AudioChannelLayout **playout)
+{
+ AVAudioSession *instance = [AVAudioSession sharedInstance];
+
+ AudioChannelLayout *layout = NULL;
+ *pdev_type = DEV_TYPE_DEFAULT;
+ NSInteger max_channel_count = [instance maximumOutputNumberOfChannels];
+
+ /* Increase the preferred number of output channels if possible */
+ if (channel_count > 2 && max_channel_count > 2)
+ {
+ channel_count = __MIN(channel_count, max_channel_count);
+ bool success = [instance setPreferredOutputNumberOfChannels:channel_count
+ error:nil];
+ if (!success || [instance outputNumberOfChannels] != channel_count)
+ {
+ /* Not critical, output channels layout will be Stereo */
+ msg_Warn(p_aout, "setPreferredOutputNumberOfChannels failed");
+ }
+ }
+
+ long last_channel_count = 0;
+ for (AVAudioSessionPortDescription *out in [[instance currentRoute] outputs])
+ {
+ /* Choose the layout with the biggest number of channels or the HDMI
+ * one */
+
+ enum dev_type dev_type;
+ if ([out.portType isEqualToString: AVAudioSessionPortUSBAudio])
+ dev_type = DEV_TYPE_USB;
+ else if ([out.portType isEqualToString: AVAudioSessionPortHDMI])
+ dev_type = DEV_TYPE_HDMI;
+ else
+ dev_type = DEV_TYPE_DEFAULT;
+
+ NSArray<AVAudioSessionChannelDescription *> *chans = [out channels];
+
+ if (chans.count > last_channel_count || dev_type == DEV_TYPE_HDMI)
+ {
+ /* We don't need a layout specification for stereo */
+ if (chans.count > 2)
+ {
+ bool labels_valid = false;
+ for (AVAudioSessionChannelDescription *chan in chans)
+ {
+ if ([chan channelLabel] != kAudioChannelLabel_Unknown)
+ {
+ labels_valid = true;
+ break;
+ }
+ }
+ if (!labels_valid)
+ {
+ /* TODO: Guess labels ? */
+ msg_Warn(p_aout, "no valid channel labels");
+ continue;
+ }
+ assert(max_channel_count >= chans.count);
+
+ if (layout == NULL
+ || layout->mNumberChannelDescriptions < chans.count)
+ {
+ const size_t layout_size = sizeof(AudioChannelLayout)
+ + chans.count * sizeof(AudioChannelDescription);
+ layout = realloc_or_free(layout, layout_size);
+ if (layout == NULL)
+ return VLC_ENOMEM;
+ }
+
+ layout->mChannelLayoutTag =
+ kAudioChannelLayoutTag_UseChannelDescriptions;
+ layout->mNumberChannelDescriptions = chans.count;
+
+ unsigned i = 0;
+ for (AVAudioSessionChannelDescription *chan in chans)
+ layout->mChannelDescriptions[i++].mChannelLabel
+ = [chan channelLabel];
+
+ last_channel_count = chans.count;
+ }
+ *pdev_type = dev_type;
+ }
+
+ if (dev_type == DEV_TYPE_HDMI) /* Prefer HDMI */
+ break;
+ }
+
+ msg_Dbg(p_aout, "Output on %s, channel count: %u",
+ *pdev_type == DEV_TYPE_HDMI ? "HDMI" :
+ *pdev_type == DEV_TYPE_USB ? "USB" : "Default",
+ layout ? layout->mNumberChannelDescriptions : 2);
+
+ *playout = layout;
+ return VLC_SUCCESS;
+}
+
+static int
avas_SetActive(audio_output_t *p_aout, bool active, NSUInteger options)
{
struct aout_sys_t * p_sys = p_aout->sys;
@@ -199,6 +305,9 @@ Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
{
struct aout_sys_t *p_sys = p_aout->sys;
OSStatus err;
+ OSStatus status;
+ AudioChannelLayout *layout = NULL;
+ AVAudioSession *instance = [AVAudioSession sharedInstance];
if (aout_FormatNbChannels(fmt) == 0
|| aout_BitsPerSample(fmt->i_format) == 0 /* No Passthrough support */)
@@ -208,13 +317,12 @@ Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
p_sys->au_unit = NULL;
+ fmt->i_format = VLC_CODEC_FL32;
+
/* Activate the AVAudioSession */
if (avas_SetActive(p_aout, true, 0) != VLC_SUCCESS)
return VLC_EGENERIC;
- fmt->i_format = VLC_CODEC_FL32;
- fmt->i_physical_channels = fmt->i_original_channels = AOUT_CHANS_STEREO;
-
p_sys->au_unit = au_NewOutputInstance(p_aout, kAudioUnitSubType_RemoteIO);
if (p_sys->au_unit == NULL)
goto error;
@@ -226,7 +334,15 @@ Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
if (err != noErr)
msg_Warn(p_aout, "failed to set IO mode [%4.4s]", (const char *)&err);
- int ret = au_Initialize(p_aout, p_sys->au_unit, fmt, NULL);
+ enum dev_type dev_type;
+ int ret = avas_GetOptimalChannelLayout(p_aout, aout_FormatNbChannels(fmt),
+ &dev_type, &layout);
+ if (ret != VLC_SUCCESS)
+ goto error;
+
+ /* TODO: Do passthrough if dev_type allows it */
+
+ ret = au_Initialize(p_aout, p_sys->au_unit, fmt, layout);
if (ret != VLC_SUCCESS)
goto error;
@@ -254,6 +370,7 @@ Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
if (p_sys->b_muted)
Pause(p_aout, true, 0);
+ free(layout);
p_aout->mute_set = MuteSet;
p_aout->pause = Pause;
msg_Dbg(p_aout, "analog AudioUnit output successfully opened "
@@ -261,6 +378,7 @@ Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
return VLC_SUCCESS;
error:
+ free(layout);
avas_SetActive(p_aout, false,
AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation);
AudioComponentInstanceDispose(p_sys->au_unit);
More information about the vlc-commits
mailing list