@@ -27,12 +27,12 @@ use libc::{c_double, c_int, c_uint};
2727use rwops:: RWops ;
2828use std:: borrow:: ToOwned ;
2929use std:: convert:: TryInto ;
30- use std:: default;
3130use std:: ffi:: { CStr , CString } ;
3231use std:: fmt;
3332use std:: marker:: PhantomData ;
3433use std:: path:: Path ;
3534use std:: str:: from_utf8;
35+ use std:: { default, ptr} ;
3636use sys;
3737use sys:: mixer;
3838use version:: Version ;
@@ -106,6 +106,16 @@ bitflags!(
106106 }
107107) ;
108108
109+ bitflags ! (
110+ /// Which audio format changes are allowed when opening a device ([`open_audio_device`]).
111+ pub struct AllowChangeFlag : u32 {
112+ const FREQUENCY = sys:: SDL_AUDIO_ALLOW_FREQUENCY_CHANGE ;
113+ const FORMAT = sys:: SDL_AUDIO_ALLOW_FORMAT_CHANGE ;
114+ const CHANNELS = sys:: SDL_AUDIO_ALLOW_CHANNELS_CHANGE ;
115+ const SAMPLES = sys:: SDL_AUDIO_ALLOW_SAMPLES_CHANGE ;
116+ }
117+ ) ;
118+
109119impl fmt:: Display for InitFlag {
110120 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
111121 <Self as fmt:: Debug >:: fmt ( self , f)
@@ -147,7 +157,8 @@ pub fn init(flags: InitFlag) -> Result<Sdl2MixerContext, String> {
147157 }
148158}
149159
150- /// Open the mixer with a certain audio format.
160+ /// Opens the default audio device for playback. If you need to select a specific audio device
161+ /// or require more fine-grained control over the device configuration, use [`open_audio_device`].
151162///
152163/// * `chunksize`: It is recommended to choose values between 256 and 1024, depending on whether
153164/// you prefer latency or compatibility. Small values reduce latency but may not
@@ -175,6 +186,60 @@ pub fn open_audio(
175186 }
176187}
177188
189+ /// Open a specific audio device for playback.
190+ ///
191+ /// (A slightly simpler version of this function is available in [`open_audio`], which still might
192+ /// meet most applications' needs.)
193+ ///
194+ /// The `allowed_changes` parameter specifies what settings are flexible. These tell `SDL_mixer`
195+ /// that the app doesn't mind if a specific setting changes. For example, the app might need stereo
196+ /// data in [`i16`] format, but if the sample rate or chunk size changes, the app can handle that.
197+ /// In that case, the app would specify `AllowChangeFlag::FORMAT | AllowChangeFlag::SAMPLES`. In
198+ /// this case, if the system's hardware requires something other than the requested format,
199+ /// `SDL_mixer` can select what the hardware demands instead of the app. For a given
200+ /// [`AllowChangeFlag`], If it is not specified, `SDL_mixer` must convert data behind the scenes
201+ /// between what the app demands and what the hardware requires. If your app needs precisely what
202+ /// is requested, specify [`AllowChangeFlag::empty`].
203+ ///
204+ /// * `frequency`: The frequency to playback audio at (in Hz).
205+ /// * `format`: Audio format ([`AudioFormat`]).
206+ /// * `channels`: Number of channels (1 is mono, 2 is stereo, etc).
207+ /// * `chunksize`: Audio buffer size in sample FRAMES (total samples divided by channel count).
208+ /// The lower the number, the lower the latency, but you risk dropouts if it gets
209+ /// too low.
210+ /// * `device`: The device name to open, or [`None`] to choose a reasonable default.
211+ /// * `allowed_changes`: Allow change flags ([`AllowChangeFlag`]).
212+ ///
213+ pub fn open_audio_device < ' a , D > (
214+ frequency : i32 ,
215+ format : AudioFormat ,
216+ channels : i32 ,
217+ chunksize : i32 ,
218+ device : D ,
219+ allowed_changes : AllowChangeFlag ,
220+ ) -> Result < ( ) , String >
221+ where
222+ D : Into < Option < & ' a str > > ,
223+ {
224+ let ret = unsafe {
225+ let device = device. into ( ) . map ( |device| CString :: new ( device) . unwrap ( ) ) ;
226+ let device_ptr = device. as_ref ( ) . map_or ( ptr:: null ( ) , |s| s. as_ptr ( ) ) ;
227+ mixer:: Mix_OpenAudioDevice (
228+ frequency as c_int ,
229+ format,
230+ channels as c_int ,
231+ chunksize as c_int ,
232+ device_ptr,
233+ allowed_changes. bits ( ) as c_int ,
234+ )
235+ } ;
236+ if ret == 0 {
237+ Ok ( ( ) )
238+ } else {
239+ Err ( get_error ( ) )
240+ }
241+ }
242+
178243/// Shutdown and cleanup the mixer API.
179244pub fn close_audio ( ) {
180245 unsafe { mixer:: Mix_CloseAudio ( ) }
0 commit comments