@@ -530,8 +530,147 @@ impl AudioDeviceBuilder {
530530 Callback :
531531 ' static + Send + FnMut ( & mut dyn AudioOutputWriter , AudioCallbackInfo ) ,
532532 {
533- let _ = callback;
534- return self . build ( ) ;
533+ if let Some ( sample_rate) = self . sample_rate {
534+ if sample_rate == 0 {
535+ return Err ( AudioError :: InvalidSampleRate {
536+ requested : sample_rate,
537+ } ) ;
538+ }
539+ }
540+
541+ if let Some ( channels) = self . channels {
542+ if channels == 0 {
543+ return Err ( AudioError :: InvalidChannels {
544+ requested : channels,
545+ } ) ;
546+ }
547+ }
548+
549+ let host = cpal_backend:: default_host ( ) ;
550+
551+ let device = host
552+ . default_output_device ( )
553+ . ok_or ( AudioError :: NoDefaultDevice ) ?;
554+
555+ let supported_configs =
556+ device. supported_output_configs ( ) . map_err ( |error| {
557+ AudioError :: SupportedConfigsUnavailable {
558+ details : error. to_string ( ) ,
559+ }
560+ } ) ?;
561+
562+ let supported_configs: Vec < cpal_backend:: SupportedStreamConfigRange > =
563+ supported_configs. collect ( ) ;
564+
565+ let selected_config = select_output_stream_config (
566+ & supported_configs,
567+ self . sample_rate ,
568+ self . channels ,
569+ ) ?;
570+
571+ let stream_config = selected_config. config ( ) ;
572+ let sample_rate = stream_config. sample_rate ;
573+ let channels = stream_config. channels ;
574+
575+ let sample_format = match selected_config. sample_format ( ) {
576+ cpal_backend:: SampleFormat :: F32 => AudioSampleFormat :: F32 ,
577+ cpal_backend:: SampleFormat :: I16 => AudioSampleFormat :: I16 ,
578+ cpal_backend:: SampleFormat :: U16 => AudioSampleFormat :: U16 ,
579+ other => {
580+ return Err ( AudioError :: UnsupportedSampleFormat {
581+ details : format ! ( "{other:?}" ) ,
582+ } ) ;
583+ }
584+ } ;
585+
586+ let callback_info = AudioCallbackInfo {
587+ sample_rate,
588+ channels,
589+ sample_format,
590+ } ;
591+
592+ let mut callback = callback;
593+
594+ let stream = match selected_config. sample_format ( ) {
595+ cpal_backend:: SampleFormat :: F32 => device
596+ . build_output_stream (
597+ & stream_config,
598+ move |data : & mut [ f32 ] , _info| {
599+ invoke_output_callback_on_buffer (
600+ channels,
601+ AudioOutputBuffer :: F32 ( data) ,
602+ callback_info,
603+ & mut callback,
604+ ) ;
605+ return ;
606+ } ,
607+ |_error| {
608+ return ;
609+ } ,
610+ None ,
611+ )
612+ . map_err ( |error| AudioError :: StreamBuildFailed {
613+ details : error. to_string ( ) ,
614+ } ) ?,
615+ cpal_backend:: SampleFormat :: I16 => device
616+ . build_output_stream (
617+ & stream_config,
618+ move |data : & mut [ i16 ] , _info| {
619+ invoke_output_callback_on_buffer (
620+ channels,
621+ AudioOutputBuffer :: I16 ( data) ,
622+ callback_info,
623+ & mut callback,
624+ ) ;
625+ return ;
626+ } ,
627+ |_error| {
628+ return ;
629+ } ,
630+ None ,
631+ )
632+ . map_err ( |error| AudioError :: StreamBuildFailed {
633+ details : error. to_string ( ) ,
634+ } ) ?,
635+ cpal_backend:: SampleFormat :: U16 => device
636+ . build_output_stream (
637+ & stream_config,
638+ move |data : & mut [ u16 ] , _info| {
639+ invoke_output_callback_on_buffer (
640+ channels,
641+ AudioOutputBuffer :: U16 ( data) ,
642+ callback_info,
643+ & mut callback,
644+ ) ;
645+ return ;
646+ } ,
647+ |_error| {
648+ return ;
649+ } ,
650+ None ,
651+ )
652+ . map_err ( |error| AudioError :: StreamBuildFailed {
653+ details : error. to_string ( ) ,
654+ } ) ?,
655+ other => {
656+ return Err ( AudioError :: UnsupportedSampleFormat {
657+ details : format ! ( "{other:?}" ) ,
658+ } ) ;
659+ }
660+ } ;
661+
662+ stream
663+ . play ( )
664+ . map_err ( |error| AudioError :: StreamPlayFailed {
665+ details : error. to_string ( ) ,
666+ } ) ?;
667+
668+ return Ok ( AudioDevice {
669+ _stream : stream,
670+ sample_rate,
671+ channels,
672+ sample_format,
673+ } ) ;
535674 }
536675}
537676
@@ -541,6 +680,20 @@ impl Default for AudioDeviceBuilder {
541680 }
542681}
543682
683+ fn invoke_output_callback_on_buffer < Callback > (
684+ channels : u16 ,
685+ buffer : AudioOutputBuffer < ' _ > ,
686+ callback_info : AudioCallbackInfo ,
687+ callback : & mut Callback ,
688+ ) where
689+ Callback : FnMut ( & mut dyn AudioOutputWriter , AudioCallbackInfo ) ,
690+ {
691+ let mut writer = InterleavedAudioOutputWriter :: new ( channels, buffer) ;
692+ writer. clear ( ) ;
693+ callback ( & mut writer, callback_info) ;
694+ return ;
695+ }
696+
544697fn sample_format_priority ( sample_format : cpal_backend:: SampleFormat ) -> u8 {
545698 match sample_format {
546699 cpal_backend:: SampleFormat :: F32 => {
@@ -733,6 +886,95 @@ mod tests {
733886 return ;
734887 }
735888
889+ #[ test]
890+ fn invoke_output_callback_on_buffer_clears_and_invokes_callback_f32 ( ) {
891+ let mut buffer_f32 = [ 1.0 , -1.0 , 0.5 , -0.5 ] ;
892+ let callback_info = AudioCallbackInfo {
893+ sample_rate : 48_000 ,
894+ channels : 2 ,
895+ sample_format : AudioSampleFormat :: F32 ,
896+ } ;
897+
898+ let mut callback_called = false ;
899+ let mut callback = |writer : & mut dyn AudioOutputWriter ,
900+ info : AudioCallbackInfo | {
901+ callback_called = true ;
902+ assert_eq ! ( info, callback_info) ;
903+ assert_eq ! ( writer. channels( ) , 2 ) ;
904+ assert_eq ! ( writer. frames( ) , 2 ) ;
905+ writer. set_sample ( 0 , 0 , 0.5 ) ;
906+ return ;
907+ } ;
908+
909+ invoke_output_callback_on_buffer (
910+ 2 ,
911+ AudioOutputBuffer :: F32 ( & mut buffer_f32) ,
912+ callback_info,
913+ & mut callback,
914+ ) ;
915+
916+ assert ! ( callback_called) ;
917+ assert_eq ! ( buffer_f32, [ 0.5 , 0.0 , 0.0 , 0.0 ] ) ;
918+ }
919+
920+ #[ test]
921+ fn invoke_output_callback_on_buffer_clears_and_invokes_callback_i16 ( ) {
922+ let mut buffer_i16 = [ 1 , -1 , 200 , -200 ] ;
923+ let callback_info = AudioCallbackInfo {
924+ sample_rate : 48_000 ,
925+ channels : 2 ,
926+ sample_format : AudioSampleFormat :: I16 ,
927+ } ;
928+
929+ let mut callback_called = false ;
930+ let mut callback = |writer : & mut dyn AudioOutputWriter ,
931+ info : AudioCallbackInfo | {
932+ callback_called = true ;
933+ assert_eq ! ( info, callback_info) ;
934+ writer. set_sample ( 0 , 0 , 1.0 ) ;
935+ return ;
936+ } ;
937+
938+ invoke_output_callback_on_buffer (
939+ 2 ,
940+ AudioOutputBuffer :: I16 ( & mut buffer_i16) ,
941+ callback_info,
942+ & mut callback,
943+ ) ;
944+
945+ assert ! ( callback_called) ;
946+ assert_eq ! ( buffer_i16, [ 32767 , 0 , 0 , 0 ] ) ;
947+ }
948+
949+ #[ test]
950+ fn invoke_output_callback_on_buffer_clears_and_invokes_callback_u16 ( ) {
951+ let mut buffer_u16 = [ 0 , 1 , 65535 , 12345 ] ;
952+ let callback_info = AudioCallbackInfo {
953+ sample_rate : 48_000 ,
954+ channels : 2 ,
955+ sample_format : AudioSampleFormat :: U16 ,
956+ } ;
957+
958+ let mut callback_called = false ;
959+ let mut callback = |writer : & mut dyn AudioOutputWriter ,
960+ info : AudioCallbackInfo | {
961+ callback_called = true ;
962+ assert_eq ! ( info, callback_info) ;
963+ writer. set_sample ( 0 , 0 , -1.0 ) ;
964+ return ;
965+ } ;
966+
967+ invoke_output_callback_on_buffer (
968+ 2 ,
969+ AudioOutputBuffer :: U16 ( & mut buffer_u16) ,
970+ callback_info,
971+ & mut callback,
972+ ) ;
973+
974+ assert ! ( callback_called) ;
975+ assert_eq ! ( buffer_u16, [ 0 , 32768 , 32768 , 32768 ] ) ;
976+ }
977+
736978 #[ test]
737979 fn writer_clear_sets_silence_for_all_formats ( ) {
738980 let mut buffer_f32 = [ 1.0 , -1.0 , 0.5 , -0.5 ] ;
0 commit comments