1 /* PROJECT: ReactOS sndrec32
2 * LICENSE: GPL - See COPYING in the top level directory
3 * FILE: base/applications/sndrec32/audio_wavein.cpp
4 * PURPOSE: Sound recording
5 * PROGRAMMERS: Marco Pagliaricci (irc: rendar)
9 #include "audio_wavein.hpp"
11 _AUDIO_NAMESPACE_START_
14 audio_wavein::init_(void)
16 ZeroMemory((LPVOID
)&wave_format
, sizeof(WAVEFORMATEX
));
17 wave_format
.cbSize
= sizeof(WAVEFORMATEX
);
21 data_flushed_event
= 0;
22 buf_secs
= _AUDIO_DEFAULT_WAVEINBUFSECS
;
23 status
= WAVEIN_NOTREADY
;
27 audio_wavein::alloc_buffers_mem_(unsigned int buffs
, float secs
)
29 unsigned int onebuf_size
= 0, tot_size
= 0;
31 /* Release old memory */
36 delete[] wave_headers
;
38 /* Calcs size of the buffers */
39 onebuf_size
= (unsigned int)((float)aud_info
.byte_rate() * secs
);
40 tot_size
= onebuf_size
* buffs
;
42 /* Allocs memory for the audio buffers */
43 main_buffer
= new BYTE
[tot_size
];
44 /* Allocs memory for the `WAVEHDR' structures */
45 wave_headers
= (WAVEHDR
*)new BYTE
[sizeof(WAVEHDR
) * buffs
];
47 ZeroMemory(main_buffer
, tot_size
);
48 ZeroMemory(wave_headers
, sizeof(WAVEHDR
) * buffs
);
49 /* Updates total size of the buffers */
54 audio_wavein::free_buffers_mem_(void)
62 delete[] wave_headers
;
69 audio_wavein::init_headers_(void)
71 /* If there is no memory for memory or headers, simply return */
72 if ((!wave_headers
) || (!main_buffer
))
75 /* This is the size for one buffer */
76 DWORD buf_sz
= mb_size
/ buffers
;
77 /* This is the base address for one buffer */
78 BYTE
*buf_addr
= main_buffer
;
79 /* Initializes headers */
80 for (unsigned int i
= 0; i
< buffers
; ++i
)
82 wave_headers
[i
].dwBufferLength
= mb_size
/ buffers
;
83 wave_headers
[i
].lpData
= (LPSTR
)buf_addr
;
89 audio_wavein::prep_headers_(void)
94 /* If there is no memory for memory or headers, throw error */
95 if ((!wave_headers
) || (!main_buffer
) || (!wavein_handle
))
97 /* TODO: throw error! */
100 for (unsigned int i
= 0; i
< buffers
; ++i
)
102 err
= waveInPrepareHeader(wavein_handle
, &wave_headers
[i
], sizeof(WAVEHDR
));
103 if (err
!= MMSYSERR_NOERROR
)
108 MessageBox(0, TEXT("waveInPrepareHeader Error."), 0, 0);
112 audio_wavein::unprep_headers_(void)
117 /* If there is no memory for memory or headers, throw error */
118 if ((!wave_headers
) || (!main_buffer
) || (!wavein_handle
))
120 /* TODO: throw error! */
123 for (unsigned int i
= 0; i
< buffers
; ++i
)
125 err
= waveInUnprepareHeader(wavein_handle
, &wave_headers
[i
], sizeof(WAVEHDR
));
126 if (err
!= MMSYSERR_NOERROR
)
131 MessageBox(0, TEXT("waveInUnPrepareHeader Error."), 0, 0);
135 audio_wavein::add_buffers_to_driver_(void)
140 /* If there is no memory for memory or headers, throw error */
141 if ((!wave_headers
) || (!main_buffer
) || (!wavein_handle
))
143 /* TODO: throw error! */
146 for (unsigned int i
= 0; i
< buffers
; ++i
)
148 err
= waveInAddBuffer(wavein_handle
, &wave_headers
[i
], sizeof(WAVEHDR
));
149 if (err
!= MMSYSERR_NOERROR
)
154 MessageBox(0, TEXT("waveInAddBuffer Error."), 0, 0);
158 audio_wavein::close(void)
160 /* If wavein object is already in the status NOTREADY, nothing to do */
161 if (status
== WAVEIN_NOTREADY
)
164 /* If the wavein is recording, then stop recording and close it */
165 if (status
== WAVEIN_RECORDING
)
168 /* Updating status */
169 status
= WAVEIN_NOTREADY
;
171 /* Waking up recording thread, so it can receive
172 the `MM_WIM_CLOSE' message then dies */
173 if (wakeup_recthread
)
174 SetEvent(wakeup_recthread
);
176 /* Closing wavein stream */
177 while ((waveInClose(wavein_handle
)) != MMSYSERR_NOERROR
)
180 /* Release buffers memory */
183 /* Re-initialize variables to the initial state */
188 audio_wavein::open(void)
191 HANDLE recthread_handle
= 0;
193 /* Checkin the status of the object */
194 if (status
!= WAVEIN_NOTREADY
)
196 /* TODO: throw error */
199 /* Creating the EVENT object that will be signaled
200 when the recording thread has to wake up */
201 wakeup_recthread
= CreateEvent(0, FALSE
, FALSE
, 0);
203 data_flushed_event
= CreateEvent(0, FALSE
, FALSE
, 0);
205 if ((!wakeup_recthread
) || (!data_flushed_event
))
208 MessageBox(0, TEXT("Thread Error."), 0, 0);
209 /* TODO: throw error */
212 /* Inialize buffers for recording audio data from the wavein audio line */
213 alloc_buffers_mem_(buffers
, buf_secs
);
216 /* Sound format that will be captured by wavein */
217 wave_format
.wFormatTag
= WAVE_FORMAT_PCM
;
218 wave_format
.nChannels
= aud_info
.channels();
219 wave_format
.nSamplesPerSec
= aud_info
.sample_rate();
220 wave_format
.wBitsPerSample
= aud_info
.bits();
221 wave_format
.nBlockAlign
= aud_info
.block_align();
222 wave_format
.nAvgBytesPerSec
= aud_info
.byte_rate();
224 /* Creating the recording thread */
225 recthread_handle
= CreateThread(NULL
,
227 audio_wavein::recording_procedure
,
231 /* Checking thread handle */
232 if (!recthread_handle
)
234 /* Updating status */
236 MessageBox(0, TEXT("Thread Error."), 0, 0);
237 /* TODO: throw error */
240 /* We don't need the thread handle anymore, so we can close it from now.
241 (We'll just need the thread ID for the `waveInOpen' API) */
242 CloseHandle(recthread_handle
);
244 /* Opening audio line wavein */
245 err
= waveInOpen(&wavein_handle
,
252 if (err
!= MMSYSERR_NOERROR
)
254 /* Updating status */
257 if (err
== WAVERR_BADFORMAT
)
258 MessageBox(0, TEXT("waveInOpen Error"), 0, 0);
260 /* TODO: throw error */
263 /* Update object status */
264 status
= WAVEIN_READY
;
266 /* Now `audio_wavein' object is ready for audio recording! */
270 audio_wavein::start_recording(void)
275 if ((status
!= WAVEIN_READY
) && (status
!= WAVEIN_STOP
))
277 /* TODO: throw error */
280 /* Updating to the recording status */
281 status
= WAVEIN_RECORDING
;
283 /* Let's prepare header of type WAVEHDR that we will pass to the driver
284 with our audio informations, and buffer informations */
287 /* The waveInAddBuffer function sends an input buffer to the given waveform-audio
288 input device. When the buffer is filled, the application is notified. */
289 add_buffers_to_driver_();
291 /* Signaling event for waking up the recorder thread */
292 ev
= SetEvent(wakeup_recthread
);
294 MessageBox(0, TEXT("Event Error."), 0, 0);
296 /* Start recording */
297 err
= waveInStart(wavein_handle
);
298 if (err
!= MMSYSERR_NOERROR
)
300 /* Updating status */
302 MessageBox(0, TEXT("waveInStart Error."), 0, 0);
303 /* TODO: throw error */
308 audio_wavein::stop_recording(void)
312 if (status
!= WAVEIN_RECORDING
)
315 status
= WAVEIN_FLUSHING
;
317 /* waveInReset will make all pending buffer as done */
318 err
= waveInReset(wavein_handle
);
319 if ( err
!= MMSYSERR_NOERROR
)
321 /* TODO: throw error */
322 MessageBox(0, TEXT("waveInReset Error."), 0, 0);
325 if (data_flushed_event
)
326 WaitForSingleObject(data_flushed_event
, INFINITE
);
329 err
= waveInStop(wavein_handle
);
330 if (err
!= MMSYSERR_NOERROR
)
332 /* TODO: throw error */
333 MessageBox(0, TEXT("waveInStop Error."), 0, 0);
336 /* The waveInUnprepareHeader function cleans up the preparation performed
337 by the waveInPrepareHeader function */
340 status
= WAVEIN_STOP
;
344 audio_wavein::recording_procedure(LPVOID arg
)
348 audio_wavein
*_this
= (audio_wavein
*)arg
;
350 /* Check the arg pointer */
354 /* The thread can go to sleep for now. It will be wake up only when
355 there is audio data to be recorded */
356 if (_this
->wakeup_recthread
)
357 WaitForSingleObject(_this
->wakeup_recthread
, INFINITE
);
359 /* If status of the `audio_wavein' object is not ready or recording the thread can exit */
360 if ((_this
->status
!= WAVEIN_READY
) && (_this
->status
!= WAVEIN_RECORDING
))
363 /* Entering main polling loop */
364 while (GetMessage(&msg
, 0, 0, 0))
369 phdr
= (WAVEHDR
*)msg
.lParam
;
371 if ((_this
->status
== WAVEIN_RECORDING
) ||
372 (_this
->status
== WAVEIN_FLUSHING
))
374 if (phdr
->dwFlags
& WHDR_DONE
)
376 /* Flushes recorded audio data to the `audio_receiver' object */
377 _this
->audio_rcvd
.audio_receive((unsigned char *)phdr
->lpData
,
378 phdr
->dwBytesRecorded
);
380 /* Updating `audio_receiver' total bytes received
381 _AFTER_ calling `audio_receive' function */
382 _this
->audio_rcvd
.bytes_received
+= phdr
->dwBytesRecorded
;
385 /* If status is not flushing data, then we can re-add the buffer
386 for reusing it. Otherwise, if we are flushing pending data,
387 we cannot re-add buffer because we don't need it anymore */
388 if (_this
->status
!= WAVEIN_FLUSHING
)
390 /* Let the audio driver reuse the buffer */
391 waveInAddBuffer(_this
->wavein_handle
, phdr
, sizeof(WAVEHDR
));
393 /* If we are flushing pending data, we have to prepare
394 to stop recording. Set WAVEHDR flag to 0, and fires
395 the event `data_flushed_event', that will wake up
396 the main thread that is sleeping into wavein_in::stop_recording()
397 member function, waiting the last `MM_WIM_DATA' message
398 that contain pending data */
401 SetEvent(_this
->data_flushed_event
);
403 /* The recording is going to stop, so the recording thread can go to sleep! */
404 WaitForSingleObject(_this
->wakeup_recthread
, INFINITE
);
406 } /* if WAVEIN_RECORDING || WAVEIN_FLUSHING */
410 /* The thread can exit now */
413 } /* end switch(msg.message) */
414 } /* end while(GetMessage(...)) */
419 _AUDIO_NAMESPACE_END_