vlc | branch: master | Thomas Guillem <[email protected]> | 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); _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
