11use projectm_rs:: core:: ProjectMHandle ;
22use sdl2:: audio:: { AudioCallback , AudioDevice , AudioSpecDesired } ;
3+ use std:: sync:: Arc ;
4+ use std:: sync:: Mutex ;
35
46use super :: config:: FrameRate ;
7+ use super :: ProjectMWrapped ;
58
69type AudioDeviceIndex = u32 ;
710type SampleFormat = f32 ; // format of audio samples
@@ -16,12 +19,13 @@ pub struct Audio {
1619 device_index : AudioDeviceIndex ,
1720 is_capturing : bool ,
1821 frame_rate : Option < FrameRate > ,
19- capturing_device : Option < AudioDevice < AudioCaptureCallback > > ,
20- projectm : ProjectMHandle ,
22+ capturing_device : Option < Box < AudioDevice < AudioCaptureCallback > > > ,
23+ projectm : ProjectMWrapped ,
2124}
2225
26+ /// Wrapper around the audio subsystem to capture audio and pass it to projectM.
2327impl Audio {
24- pub fn new ( sdl_context : & sdl2:: Sdl , projectm : ProjectMHandle ) -> Self {
28+ pub fn new ( sdl_context : & sdl2:: Sdl , projectm : ProjectMWrapped ) -> Self {
2529 let audio_subsystem = sdl_context. audio ( ) . unwrap ( ) ;
2630
2731 Self {
@@ -52,7 +56,8 @@ impl Audio {
5256 }
5357 }
5458
55- pub fn set_device ( & mut self , device_index : AudioDeviceIndex ) {
59+ /// Start capturing audio from device_index.
60+ pub fn capture_device ( & mut self , device_index : AudioDeviceIndex ) {
5661 self . stop_audio_capture ( ) ;
5762 self . device_index = device_index;
5863 self . begin_audio_capture ( ) ;
@@ -64,12 +69,14 @@ impl Audio {
6469 . expect ( "could not get audio device" )
6570 }
6671
72+ /// Select a new audio device and start capturing audio from it.
6773 pub fn open_next_device ( & mut self ) {
6874 let device_list = self . get_device_list ( ) ;
6975 let current_device_index = self . device_index ;
7076
71- let next_device_index = current_device_index + 1 % device_list. len ( ) as AudioDeviceIndex ;
72- self . set_device ( next_device_index) ;
77+ let next_device_index = ( current_device_index + 1 ) % device_list. len ( ) as AudioDeviceIndex ;
78+ println ! ( "Opening next device: {}" , next_device_index) ;
79+ self . capture_device ( next_device_index) ;
7380 }
7481
7582 fn get_device_list ( & self ) -> Vec < AudioCaptureDevice > {
@@ -96,66 +103,75 @@ impl Audio {
96103 let sample_rate: u32 = 44100 ;
97104 let frame_rate = self . frame_rate . unwrap ( ) ;
98105
99- // should be enough for 1 frame
100- let buffer_size = ( sample_rate / frame_rate) as u16 ;
106+ // how many samples to capture at a time
107+ // should be enough for 1 frame or less
108+ // should not be larger than max_samples / channels
109+ let max_samples: usize = projectm_rs:: core:: Projectm :: pcm_get_max_samples ( )
110+ . try_into ( )
111+ . unwrap ( ) ;
112+ let samples_per_frame = ( sample_rate / frame_rate) as usize ;
113+ let buffer_size = std:: cmp:: min ( max_samples / 2 , samples_per_frame) ;
114+ println ! ( "Buffer size: {}" , buffer_size) ;
101115
102116 let desired_spec = AudioSpecDesired {
103117 freq : Some ( sample_rate. try_into ( ) . unwrap ( ) ) ,
104118 channels : Some ( 2 ) ,
105- samples : Some ( buffer_size) ,
119+ samples : Some ( buffer_size. try_into ( ) . unwrap ( ) ) ,
106120 } ;
107121
108- let audio_device = self
122+ // open audio device for capture
123+ let device_name = self . get_current_device_name ( ) ;
124+ let audio_device = match self
109125 . audio_subsystem // sdl
110- . open_capture ( None , & desired_spec, |_spec| {
111- println ! (
112- "Beginning audio capture for device {}" ,
113- self . get_current_device_name( )
114- ) ;
126+ . open_capture ( device_name. as_str ( ) , & desired_spec, |_spec| {
127+ println ! ( "Beginning audio capture for device {}" , device_name) ;
115128
116129 // print spec
117130 println ! ( "Audio Spec: {:?}" , _spec) ;
118131
119132 // return callback fn
120133 AudioCaptureCallback {
121- pm : self . projectm ,
122- // spec,
123- // buffer_size,
124- // buffer: vec![0; buffer_size as usize],
125- // position: 0,
134+ pm : self . projectm . clone ( ) ,
126135 }
127- } )
128- . unwrap ( ) ;
136+ } ) {
137+ Ok ( device) => device,
138+ Err ( e) => {
139+ println ! ( "Error opening audio device: {}" , e) ;
140+ return ;
141+ }
142+ } ;
143+
144+ // start capturing
145+ audio_device. resume ( ) ;
129146
130147 // take ownership of device
131- self . capturing_device = Some ( audio_device) ;
148+ self . capturing_device = Some ( Box :: new ( audio_device) ) ;
132149 self . is_capturing = true ;
133-
134- // play device
135- self . capturing_device . as_mut ( ) . unwrap ( ) . resume ( ) ;
136150 }
137151
138152 pub fn stop_audio_capture ( & mut self ) {
139153 let current_device_name = self . get_current_device_name ( ) ;
140154 println ! ( "Stopping audio capture for device {}" , current_device_name) ;
141155
142156 println ! (
143- "current capture device: {:?}" ,
157+ "Current capture device status : {:?}" ,
144158 self . capturing_device. as_ref( ) . unwrap( ) . status( )
145159 ) ;
146160
161+ // take ownership of device
162+ // capture device will be dropped when this function returns
163+ // and the audio callback will stop being called
164+ let device = self . capturing_device . take ( ) . unwrap ( ) ;
165+ device. pause ( ) ;
166+
147167 self . is_capturing = false ;
148- // drop(self.capturing_device); // stop capturing
149- self . capturing_device = None ;
150168 }
151169}
152170
153171struct AudioCaptureCallback {
154- pm : ProjectMHandle ,
155- // spec: sdl2::audio::AudioSpec,
156- // buffer_size: SampleFormat,
157- // buffer: Vec<u8>,
158- // position: usize,
172+ // we need to keep a reference to the projectm instance to
173+ // add the audio data to it
174+ pm : Arc < Mutex < ProjectMHandle > > ,
159175}
160176unsafe impl Send for AudioCaptureCallback { }
161177unsafe impl Sync for AudioCaptureCallback { }
@@ -166,7 +182,7 @@ impl AudioCallback for AudioCaptureCallback {
166182 // we are receiving some chunk of audio data
167183 // we need to pass it to projectm
168184 fn callback ( & mut self , out : & mut [ SampleFormat ] ) {
169- let pm = self . pm ;
185+ let pm = * self . pm . lock ( ) . unwrap ( ) ;
170186 projectm_rs:: core:: Projectm :: pcm_add_float ( pm, out. to_vec ( ) , 2 ) ;
171187 }
172188}
0 commit comments