@@ -805,40 +805,135 @@ fn get_setup() -> Setup {
805805 exit ( 1 ) ;
806806 } ) ;
807807
808+ let is_alsa_mixer = match mixer_type. as_deref ( ) {
809+ #[ cfg( feature = "alsa-backend" ) ]
810+ Some ( AlsaMixer :: NAME ) => true ,
811+ _ => false ,
812+ } ;
813+
814+ #[ cfg( feature = "alsa-backend" ) ]
815+ if !is_alsa_mixer {
816+ for a in & [ ALSA_MIXER_DEVICE , ALSA_MIXER_INDEX , ALSA_MIXER_CONTROL ] {
817+ if opt_present ( a) {
818+ warn ! ( "Alsa specific mixer options have no effect if not using the alsa mixer." ) ;
819+ break ;
820+ }
821+ }
822+ }
823+
808824 let mixer_config = {
809825 let mixer_default_config = MixerConfig :: default ( ) ;
810826
811827 #[ cfg( feature = "alsa-backend" ) ]
812- let device = opt_str ( ALSA_MIXER_DEVICE ) . unwrap_or_else ( || {
813- if let Some ( ref device_name) = device {
814- device_name. to_string ( )
815- } else {
816- mixer_default_config. device . clone ( )
817- }
818- } ) ;
828+ let index = if !is_alsa_mixer {
829+ mixer_default_config. index
830+ } else {
831+ opt_str ( ALSA_MIXER_INDEX )
832+ . map ( |index| {
833+ index. parse :: < u32 > ( ) . unwrap_or_else ( |_| {
834+ invalid_error_msg (
835+ ALSA_MIXER_INDEX ,
836+ ALSA_MIXER_INDEX_SHORT ,
837+ & index,
838+ "" ,
839+ & mixer_default_config. index . to_string ( ) ,
840+ ) ;
841+
842+ exit ( 1 ) ;
843+ } )
844+ } )
845+ . unwrap_or_else ( || match device {
846+ // Look for the dev index portion of --device.
847+ // Specifically <dev index> when --device is <something>:CARD=<card name>,DEV=<dev index>
848+ // or <something>:<card index>,<dev index>.
849+
850+ // If --device does not contain a ',' it does not contain a dev index.
851+ // In the case that the dev index is omitted it is assumed to be 0 (mixer_default_config.index).
852+ // Malformed --device values will also fallback to mixer_default_config.index.
853+ Some ( ref device_name) if device_name. contains ( ',' ) => {
854+ // Turn <something>:CARD=<card name>,DEV=<dev index> or <something>:<card index>,<dev index>
855+ // into DEV=<dev index> or <dev index>.
856+ let dev = & device_name[ device_name. find ( ',' ) . unwrap_or_default ( ) ..]
857+ . trim_start_matches ( ',' ) ;
858+
859+ // Turn DEV=<dev index> into <dev index> (noop if it's already <dev index>)
860+ // and then parse <dev index>.
861+ // Malformed --device values will fail the parse and fallback to mixer_default_config.index.
862+ dev[ dev. find ( '=' ) . unwrap_or_default ( ) ..]
863+ . trim_start_matches ( '=' )
864+ . parse :: < u32 > ( )
865+ . unwrap_or ( mixer_default_config. index )
866+ }
867+ _ => mixer_default_config. index ,
868+ } )
869+ } ;
819870
820871 #[ cfg( not( feature = "alsa-backend" ) ) ]
821- let device = mixer_default_config. device ;
872+ let index = mixer_default_config. index ;
822873
823874 #[ cfg( feature = "alsa-backend" ) ]
824- let index = opt_str ( ALSA_MIXER_INDEX )
825- . map ( |index| {
826- index. parse :: < u32 > ( ) . unwrap_or_else ( |_| {
827- invalid_error_msg (
828- ALSA_MIXER_INDEX ,
829- ALSA_MIXER_INDEX_SHORT ,
830- & index,
831- "" ,
832- & mixer_default_config. index . to_string ( ) ,
833- ) ;
875+ let device = if !is_alsa_mixer {
876+ mixer_default_config. device
877+ } else {
878+ match opt_str ( ALSA_MIXER_DEVICE ) {
879+ Some ( mixer_device) => {
880+ if mixer_device. is_empty ( ) {
881+ empty_string_error_msg ( ALSA_MIXER_DEVICE , ALSA_MIXER_DEVICE_SHORT ) ;
882+ }
834883
835- exit ( 1 ) ;
836- } )
837- } )
838- . unwrap_or_else ( || mixer_default_config. index ) ;
884+ mixer_device
885+ }
886+ None => match device {
887+ Some ( ref device_name) => {
888+ // Look for the card name or card index portion of --device.
889+ // Specifically <card name> when --device is <something>:CARD=<card name>,DEV=<dev index>
890+ // or card index when --device is <something>:<card index>,<dev index>.
891+ // --device values like `pulse`, `default`, `jack` may be valid but there is no way to
892+ // infer automatically what the mixer should be so they fail auto fallback
893+ // so --alsa-mixer-device must be manually specified in those situations.
894+ let start_index = device_name. find ( ':' ) . unwrap_or_default ( ) ;
895+
896+ let end_index = match device_name. find ( ',' ) {
897+ Some ( index) if index > start_index => index,
898+ _ => device_name. len ( ) ,
899+ } ;
900+
901+ let card = & device_name[ start_index..end_index] ;
902+
903+ if card. starts_with ( ':' ) {
904+ // mixers are assumed to be hw:CARD=<card name> or hw:<card index>.
905+ "hw" . to_owned ( ) + card
906+ } else {
907+ error ! (
908+ "Could not find an alsa mixer for \" {}\" , it must be specified with `--{}` / `-{}`" ,
909+ & device. unwrap_or_default( ) ,
910+ ALSA_MIXER_DEVICE ,
911+ ALSA_MIXER_DEVICE_SHORT
912+ ) ;
913+
914+ exit ( 1 ) ;
915+ }
916+ }
917+ None => {
918+ error ! (
919+ "`--{}` / `-{}` or `--{}` / `-{}` \
920+ must be specified when `--{}` / `-{}` is set to \" alsa\" ",
921+ DEVICE ,
922+ DEVICE_SHORT ,
923+ ALSA_MIXER_DEVICE ,
924+ ALSA_MIXER_DEVICE_SHORT ,
925+ MIXER_TYPE ,
926+ MIXER_TYPE_SHORT
927+ ) ;
928+
929+ exit ( 1 ) ;
930+ }
931+ } ,
932+ }
933+ } ;
839934
840935 #[ cfg( not( feature = "alsa-backend" ) ) ]
841- let index = mixer_default_config. index ;
936+ let device = mixer_default_config. device ;
842937
843938 #[ cfg( feature = "alsa-backend" ) ]
844939 let control = opt_str ( ALSA_MIXER_CONTROL ) . unwrap_or ( mixer_default_config. control ) ;
@@ -881,10 +976,12 @@ fn get_setup() -> Setup {
881976 exit ( 1 ) ;
882977 }
883978 } )
884- . unwrap_or_else ( || match mixer_type. as_deref ( ) {
885- #[ cfg( feature = "alsa-backend" ) ]
886- Some ( AlsaMixer :: NAME ) => 0.0 , // let alsa query the control
887- _ => VolumeCtrl :: DEFAULT_DB_RANGE ,
979+ . unwrap_or_else ( || {
980+ if is_alsa_mixer {
981+ 0.0
982+ } else {
983+ VolumeCtrl :: DEFAULT_DB_RANGE
984+ }
888985 } ) ;
889986
890987 let volume_ctrl = opt_str ( VOLUME_CTRL )
@@ -1093,10 +1190,12 @@ fn get_setup() -> Setup {
10931190
10941191 ( volume as f32 / 100.0 * VolumeCtrl :: MAX_VOLUME as f32 ) as u16
10951192 } )
1096- . or_else ( || match mixer_type. as_deref ( ) {
1097- #[ cfg( feature = "alsa-backend" ) ]
1098- Some ( AlsaMixer :: NAME ) => None ,
1099- _ => cache. as_ref ( ) . and_then ( Cache :: volume) ,
1193+ . or_else ( || {
1194+ if is_alsa_mixer {
1195+ None
1196+ } else {
1197+ cache. as_ref ( ) . and_then ( Cache :: volume)
1198+ }
11001199 } ) ;
11011200
11021201 let device_type = opt_str ( DEVICE_TYPE )
0 commit comments