@@ -4,7 +4,6 @@ extern crate libc;
44use std:: {
55 cell:: Cell ,
66 cmp, fmt,
7- ops:: RangeInclusive ,
87 sync:: { Arc , Mutex } ,
98 thread:: { self , JoinHandle } ,
109 time:: Duration ,
@@ -28,12 +27,6 @@ pub type SupportedOutputConfigs = VecIntoIter<SupportedStreamConfigRange>;
2827
2928mod enumerate;
3029
31- const VALID_BUFFER_SIZE : RangeInclusive < alsa:: pcm:: Frames > =
32- 1 ..=FrameCount :: MAX as alsa:: pcm:: Frames ;
33-
34- const FALLBACK_PERIOD_TIME : u32 = 25_000 ;
35- const PREFERRED_PERIOD_COUNT : u32 = 2 ;
36-
3730/// The default linux, dragonfly, freebsd and netbsd host type.
3831#[ derive( Debug ) ]
3932pub struct Host ;
@@ -1125,143 +1118,31 @@ fn set_hw_params_from_format(
11251118 }
11261119 } ;
11271120
1121+ // Set the sample format, rate, and channels - if this fails, the format is not supported.
11281122 hw_params. set_format ( sample_format) ?;
11291123 hw_params. set_rate ( config. sample_rate . 0 , alsa:: ValueOr :: Nearest ) ?;
11301124 hw_params. set_channels ( config. channels as u32 ) ?;
11311125
1132- if !set_hw_params_periods ( & hw_params, config. buffer_size ) {
1133- return Err ( BackendSpecificError {
1134- description : format ! (
1135- "Buffer size '{:?}' is not supported by this backend" ,
1136- config. buffer_size
1137- ) ,
1138- } ) ;
1126+ // Set buffer size if requested. ALSA will calculate the period size from this buffer size as:
1127+ // period_size = nearest_set_buffer_size / default_periods
1128+ //
1129+ // If not requested, ALSA will calculate the period size from the device defaults:
1130+ // period_size = default_buffer_size / default_periods
1131+ if let BufferSize :: Fixed ( buffer_size) = config. buffer_size {
1132+ hw_params
1133+ . set_buffer_size_near ( buffer_size as _ )
1134+ . map_err ( |_| BackendSpecificError {
1135+ description : format ! (
1136+ "Buffer size '{:?}' is not supported by this backend" ,
1137+ config. buffer_size
1138+ ) ,
1139+ } ) ?;
11391140 }
1140-
11411141 pcm_handle. hw_params ( & hw_params) ?;
11421142
11431143 Ok ( hw_params. can_pause ( ) )
11441144}
11451145
1146- /// Returns true if the periods were reasonably set. A false result indicates the device default
1147- /// configuration is being used.
1148- fn set_hw_params_periods ( hw_params : & alsa:: pcm:: HwParams , buffer_size : BufferSize ) -> bool {
1149- // TODO: When the API is made available, this could rely on snd_pcm_hw_params_get_periods_min
1150- // and snd_pcm_hw_params_get_periods_max
1151- hw_params
1152- . set_periods ( PREFERRED_PERIOD_COUNT , alsa:: ValueOr :: Greater )
1153- . unwrap_or_default ( ) ;
1154-
1155- let Some ( period_count) = hw_params
1156- . get_periods ( )
1157- . ok ( )
1158- . filter ( |& period_count| period_count > 0 )
1159- else {
1160- return false ;
1161- } ;
1162-
1163- /// Returns true if the buffer size was reasonably set.
1164- ///
1165- /// The buffer is a ring buffer. The buffer size always has to be greater than one period size.
1166- /// Commonly this is 2*period size, but some hardware can do 8 periods per buffer. It is also
1167- /// possible for the buffer size to not be an integer multiple of the period size.
1168- ///
1169- /// See: https://www.alsa-project.org/wiki/FramesPeriods
1170- fn set_hw_params_buffer_size (
1171- hw_params : & alsa:: pcm:: HwParams ,
1172- period_count : u32 ,
1173- mut buffer_size : FrameCount ,
1174- ) -> bool {
1175- buffer_size = {
1176- let ( min_buffer_size, max_buffer_size) = hw_params_buffer_size_min_max ( hw_params) ;
1177- buffer_size. clamp ( min_buffer_size, max_buffer_size)
1178- } ;
1179-
1180- // Use time-based period configuration for device compatibility. Some devices have better
1181- // compatibility with set_period_time_near() than set_period_size_near(). Calculate a
1182- // period time that works with the requested buffer.
1183-
1184- // Calculate desired period time based on buffer size and period count.
1185- // We can't yet get period_time constraints from alsa-rs, so we'll use period_size
1186- // constraints and convert them to time constraints.
1187- let ( min_period_size, max_period_size) = match (
1188- hw_params. get_period_size_min ( ) ,
1189- hw_params. get_period_size_max ( ) ,
1190- ) {
1191- ( Ok ( min) , Ok ( max) ) => ( min, max) ,
1192- _ => {
1193- // Fall back to a safe default if we can't get constraints
1194- let Ok ( _) =
1195- hw_params. set_period_time_near ( FALLBACK_PERIOD_TIME , alsa:: ValueOr :: Nearest )
1196- else {
1197- return false ;
1198- } ;
1199- let Ok ( actual_buffer_size) = hw_params. set_buffer_size_near ( buffer_size as _ )
1200- else {
1201- return false ;
1202- } ;
1203- return VALID_BUFFER_SIZE . contains ( & actual_buffer_size) ;
1204- }
1205- } ;
1206-
1207- // Calculate desired period size and convert to time
1208- // period_time = (period_size_frames / sample_rate) * 1_000_000 microseconds
1209- let desired_period_size_frames =
1210- ( buffer_size / period_count) . clamp ( min_period_size as u32 , max_period_size as u32 ) ;
1211-
1212- // Get actual sample rate that was set (don't assume 44100)
1213- if let Ok ( sample_rate) = hw_params. get_rate ( ) {
1214- let desired_period_time_us =
1215- ( desired_period_size_frames as u64 * 1_000_000 ) / sample_rate as u64 ;
1216-
1217- // Set the period time
1218- let Ok ( _) = hw_params
1219- . set_period_time_near ( desired_period_time_us as u32 , alsa:: ValueOr :: Nearest )
1220- else {
1221- return false ;
1222- } ;
1223- }
1224-
1225- // Now set the buffer size to the user's requested size
1226- let Ok ( actual_buffer_size) = hw_params. set_buffer_size_near ( buffer_size as _ ) else {
1227- return false ;
1228- } ;
1229-
1230- // Double-check the set size is within the CPAL range
1231- VALID_BUFFER_SIZE . contains ( & actual_buffer_size)
1232- }
1233-
1234- if let BufferSize :: Fixed ( val) = buffer_size {
1235- return set_hw_params_buffer_size ( hw_params, period_count, val) ;
1236- }
1237-
1238- if hw_params
1239- . set_period_time_near ( FALLBACK_PERIOD_TIME , alsa:: ValueOr :: Nearest )
1240- . is_err ( )
1241- {
1242- return false ;
1243- }
1244-
1245- let period_size = if let Ok ( period_size) = hw_params. get_period_size ( ) {
1246- period_size
1247- } else {
1248- return false ;
1249- } ;
1250-
1251- // We should not fail if the driver is unhappy here.
1252- // `default` pcm sometimes fails here, but there no reason to as we attempt to provide a size or
1253- // minimum number of periods.
1254- let Ok ( buffer_size) =
1255- hw_params. set_buffer_size_near ( period_size * period_count as alsa:: pcm:: Frames )
1256- else {
1257- return hw_params. set_buffer_size_min ( 1 ) . is_ok ( )
1258- && hw_params. set_buffer_size_max ( FrameCount :: MAX as _ ) . is_ok ( ) ;
1259- } ;
1260-
1261- // Double-check the set size is within the CPAL range
1262- VALID_BUFFER_SIZE . contains ( & buffer_size)
1263- }
1264-
12651146fn set_sw_params_from_format (
12661147 pcm_handle : & alsa:: pcm:: PCM ,
12671148 config : & StreamConfig ,
0 commit comments