@@ -31,8 +31,8 @@ use objc2_core_audio::{
3131 kAudioDevicePropertyLatency, kAudioDevicePropertyNominalSampleRate,
3232 kAudioDevicePropertySafetyOffset, kAudioDevicePropertyStreamConfiguration,
3333 kAudioDevicePropertyStreamFormat, kAudioObjectPropertyClass, kAudioObjectPropertyElementMain,
34- kAudioObjectPropertyScopeGlobal , kAudioObjectPropertyScopeInput ,
35- kAudioObjectPropertyScopeOutput,
34+ kAudioObjectPropertyElementName , kAudioObjectPropertyScopeGlobal ,
35+ kAudioObjectPropertyScopeInput , kAudioObjectPropertyScopeOutput,
3636} ;
3737use objc2_core_audio_types:: {
3838 AudioBuffer , AudioBufferList , AudioStreamBasicDescription , AudioValueRange ,
@@ -357,6 +357,10 @@ impl DeviceTrait for Device {
357357 timeout,
358358 )
359359 }
360+
361+ fn get_channel_name ( & self , channel_index : u16 , input : bool ) -> Result < String , Error > {
362+ Device :: get_channel_name ( self , channel_index, input)
363+ }
360364}
361365
362366#[ derive( Clone ) ]
@@ -690,6 +694,24 @@ impl Device {
690694 . map ( |mut configs| configs. next ( ) . is_some ( ) )
691695 . unwrap_or ( false )
692696 }
697+
698+ fn get_channel_name ( & self , channel_index : u16 , input : bool ) -> Result < String , Error > {
699+ if input && !self . supports_input ( ) {
700+ return Err ( Error :: with_message (
701+ ErrorKind :: InvalidInput ,
702+ "Device does not support input" ,
703+ ) ) ;
704+ }
705+
706+ if !input && !self . supports_output ( ) {
707+ return Err ( Error :: with_message (
708+ ErrorKind :: InvalidInput ,
709+ "Device does not support output" ,
710+ ) ) ;
711+ }
712+
713+ get_channel_name_for_device ( self . audio_device_id , channel_index, input)
714+ }
693715}
694716
695717impl Device {
@@ -1116,3 +1138,45 @@ pub(crate) fn get_device_buffer_frame_size(
11161138 ) ?;
11171139 Ok ( frames as usize )
11181140}
1141+
1142+ fn get_channel_name_for_device (
1143+ device_id : AudioDeviceID ,
1144+ channel_index : u16 ,
1145+ input : bool ,
1146+ ) -> Result < String , Error > {
1147+ let mut channel_name: * mut CFString = std:: ptr:: null_mut ( ) ;
1148+ let mut data_size = size_of :: < * mut CFString > ( ) as u32 ;
1149+
1150+ let property_address = AudioObjectPropertyAddress {
1151+ mSelector : kAudioObjectPropertyElementName,
1152+ mScope : if input {
1153+ kAudioObjectPropertyScopeInput
1154+ } else {
1155+ kAudioObjectPropertyScopeOutput
1156+ } ,
1157+ // Channels numbers start on 1 here
1158+ mElement : channel_index as u32 + 1 ,
1159+ } ;
1160+
1161+ let status = unsafe {
1162+ AudioObjectGetPropertyData (
1163+ device_id,
1164+ NonNull :: from ( & property_address) ,
1165+ 0 ,
1166+ null ( ) ,
1167+ NonNull :: from ( & mut data_size) ,
1168+ NonNull :: from ( & mut channel_name) . cast ( ) ,
1169+ )
1170+ } ;
1171+ check_os_status ( status) ?;
1172+
1173+ if !channel_name. is_null ( ) {
1174+ let raw_name = unsafe { CFRetained :: from_raw ( NonNull :: new ( channel_name) . unwrap ( ) ) } ;
1175+ Ok ( raw_name. to_string ( ) )
1176+ } else {
1177+ Err ( Error :: with_message (
1178+ ErrorKind :: Other ,
1179+ "channel name is null" ,
1180+ ) )
1181+ }
1182+ }
0 commit comments