ReactOS  0.4.12-dev-57-g7050ac4
audio_wavein.cpp
Go to the documentation of this file.
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)
6  */
7 
8 #include "stdafx.h"
9 #include "audio_wavein.hpp"
10 
12 
13 void
15 {
17  wave_format.cbSize = sizeof(WAVEFORMATEX);
18  wavein_handle = 0;
19  recthread_id = 0;
20  wakeup_recthread = 0;
24 }
25 
26 void
27 audio_wavein::alloc_buffers_mem_(unsigned int buffs, float secs)
28 {
29  unsigned int onebuf_size = 0, tot_size = 0;
30 
31  /* Release old memory */
32  if (main_buffer)
33  delete[] main_buffer;
34 
35  if (wave_headers)
36  delete[] wave_headers;
37 
38  /* Calcs size of the buffers */
39  onebuf_size = (unsigned int)((float)aud_info.byte_rate() * secs);
40  tot_size = onebuf_size * buffs;
41 
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];
46  /* Zeros memory */
47  ZeroMemory(main_buffer, tot_size);
48  ZeroMemory(wave_headers, sizeof(WAVEHDR) * buffs);
49  /* Updates total size of the buffers */
50  mb_size = tot_size;
51 }
52 
53 void
55 {
56  /* Frees memory */
57  if (main_buffer)
58  delete[] main_buffer;
59 
60 
61  if (wave_headers)
62  delete[] wave_headers;
63 
64  main_buffer = 0;
65  wave_headers = 0;
66 }
67 
68 void
70 {
71  /* If there is no memory for memory or headers, simply return */
72  if ((!wave_headers) || (!main_buffer))
73  return;
74 
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)
81  {
83  wave_headers[i].lpData = (LPSTR)buf_addr;
84  buf_addr += buf_sz;
85  }
86 }
87 
88 void
90 {
91  MMRESULT err;
92  bool error = false;
93 
94  /* If there is no memory for memory or headers, throw error */
95  if ((!wave_headers) || (!main_buffer) || (!wavein_handle))
96  {
97  /* TODO: throw error! */
98  }
99 
100  for (unsigned int i = 0; i < buffers; ++i)
101  {
103  if (err != MMSYSERR_NOERROR)
104  error = true;
105  }
106 
107  if (error)
108  MessageBox(0, TEXT("waveInPrepareHeader Error."), 0, 0);
109 }
110 
111 void
113 {
114  MMRESULT err;
115  bool error = false;
116 
117  /* If there is no memory for memory or headers, throw error */
118  if ((!wave_headers) || (!main_buffer) || (!wavein_handle))
119  {
120  /* TODO: throw error! */
121  }
122 
123  for (unsigned int i = 0; i < buffers; ++i)
124  {
126  if (err != MMSYSERR_NOERROR)
127  error = true;
128  }
129 
130  if (error)
131  MessageBox(0, TEXT("waveInUnPrepareHeader Error."), 0, 0);
132 }
133 
134 void
136 {
137  MMRESULT err;
138  bool error = false;
139 
140  /* If there is no memory for memory or headers, throw error */
141  if ((!wave_headers) || (!main_buffer) || (!wavein_handle))
142  {
143  /* TODO: throw error! */
144  }
145 
146  for (unsigned int i = 0; i < buffers; ++i)
147  {
149  if (err != MMSYSERR_NOERROR)
150  error = true;
151  }
152 
153  if (error)
154  MessageBox(0, TEXT("waveInAddBuffer Error."), 0, 0);
155 }
156 
157 void
159 {
160  /* If wavein object is already in the status NOTREADY, nothing to do */
161  if (status == WAVEIN_NOTREADY)
162  return;
163 
164  /* If the wavein is recording, then stop recording and close it */
165  if (status == WAVEIN_RECORDING)
166  stop_recording();
167 
168  /* Updating status */
170 
171  /* Waking up recording thread, so it can receive
172  the `MM_WIM_CLOSE' message then dies */
173  if (wakeup_recthread)
175 
176  /* Closing wavein stream */
178  Sleep(1);
179 
180  /* Release buffers memory */
182 
183  /* Re-initialize variables to the initial state */
184  init_();
185 }
186 
187 void
189 {
190  MMRESULT err;
191  HANDLE recthread_handle = 0;
192 
193  /* Checkin the status of the object */
194  if (status != WAVEIN_NOTREADY)
195  {
196  /* TODO: throw error */
197  }
198 
199  /* Creating the EVENT object that will be signaled
200  when the recording thread has to wake up */
202 
204 
206  {
207  status = WAVEIN_ERR;
208  MessageBox(0, TEXT("Thread Error."), 0, 0);
209  /* TODO: throw error */
210  }
211 
212  /* Inialize buffers for recording audio data from the wavein audio line */
214  init_headers_();
215 
216  /* Sound format that will be captured by wavein */
223 
224  /* Creating the recording thread */
225  recthread_handle = CreateThread(NULL,
226  0,
228  (PVOID)this,
229  0,
230  &recthread_id);
231  /* Checking thread handle */
232  if (!recthread_handle)
233  {
234  /* Updating status */
235  status = WAVEIN_ERR;
236  MessageBox(0, TEXT("Thread Error."), 0, 0);
237  /* TODO: throw error */
238  }
239 
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);
243 
244  /* Opening audio line wavein */
245  err = waveInOpen(&wavein_handle,
246  0,
247  &wave_format,
248  recthread_id,
249  0,
251 
252  if (err != MMSYSERR_NOERROR)
253  {
254  /* Updating status */
255  status = WAVEIN_ERR;
256 
257  if (err == WAVERR_BADFORMAT)
258  MessageBox(0, TEXT("waveInOpen Error"), 0, 0);
259 
260  /* TODO: throw error */
261  }
262 
263  /* Update object status */
265 
266  /* Now `audio_wavein' object is ready for audio recording! */
267 }
268 
269 void
271 {
272  MMRESULT err;
273  BOOL ev;
274 
275  if ((status != WAVEIN_READY) && (status != WAVEIN_STOP))
276  {
277  /* TODO: throw error */
278  }
279 
280  /* Updating to the recording status */
282 
283  /* Let's prepare header of type WAVEHDR that we will pass to the driver
284  with our audio informations, and buffer informations */
285  prep_headers_();
286 
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. */
290 
291  /* Signaling event for waking up the recorder thread */
293  if (!ev)
294  MessageBox(0, TEXT("Event Error."), 0, 0);
295 
296  /* Start recording */
297  err = waveInStart(wavein_handle);
298  if (err != MMSYSERR_NOERROR)
299  {
300  /* Updating status */
301  status = WAVEIN_ERR;
302  MessageBox(0, TEXT("waveInStart Error."), 0, 0);
303  /* TODO: throw error */
304  }
305 }
306 
307 void
309 {
310  MMRESULT err;
311 
312  if (status != WAVEIN_RECORDING)
313  return;
314 
316 
317  /* waveInReset will make all pending buffer as done */
318  err = waveInReset(wavein_handle);
319  if ( err != MMSYSERR_NOERROR )
320  {
321  /* TODO: throw error */
322  MessageBox(0, TEXT("waveInReset Error."), 0, 0);
323  }
324 
325  if (data_flushed_event)
327 
328  /* Stop recording */
329  err = waveInStop(wavein_handle);
330  if (err != MMSYSERR_NOERROR)
331  {
332  /* TODO: throw error */
333  MessageBox(0, TEXT("waveInStop Error."), 0, 0);
334  }
335 
336  /* The waveInUnprepareHeader function cleans up the preparation performed
337  by the waveInPrepareHeader function */
338  unprep_headers_();
339 
341 }
342 
343 DWORD WINAPI
345 {
346  MSG msg;
347  WAVEHDR *phdr;
348  audio_wavein *_this = (audio_wavein *)arg;
349 
350  /* Check the arg pointer */
351  if (_this == 0)
352  return 0;
353 
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)
358 
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))
361  return 0;
362 
363  /* Entering main polling loop */
364  while (GetMessage(&msg, 0, 0, 0))
365  {
366  switch (msg.message)
367  {
368  case MM_WIM_DATA:
369  phdr = (WAVEHDR *)msg.lParam;
370 
371  if ((_this->status == WAVEIN_RECORDING) ||
372  (_this->status == WAVEIN_FLUSHING))
373  {
374  if (phdr->dwFlags & WHDR_DONE)
375  {
376  /* Flushes recorded audio data to the `audio_receiver' object */
377  _this->audio_rcvd.audio_receive((unsigned char *)phdr->lpData,
378  phdr->dwBytesRecorded);
379 
380  /* Updating `audio_receiver' total bytes received
381  _AFTER_ calling `audio_receive' function */
382  _this->audio_rcvd.bytes_received += phdr->dwBytesRecorded;
383  }
384 
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)
389  {
390  /* Let the audio driver reuse the buffer */
391  waveInAddBuffer(_this->wavein_handle, phdr, sizeof(WAVEHDR));
392  } else {
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 */
399 
400  phdr->dwFlags = 0;
402 
403  /* The recording is going to stop, so the recording thread can go to sleep! */
405  }
406  } /* if WAVEIN_RECORDING || WAVEIN_FLUSHING */
407  break;
408 
409  case MM_WIM_CLOSE:
410  /* The thread can exit now */
411  return 0;
412  break;
413  } /* end switch(msg.message) */
414  } /* end while(GetMessage(...)) */
415 
416  return 0;
417 }
418 
#define CreateEvent
Definition: winbase.h:3562
void free_buffers_mem_(void)
#define WAVERR_BADFORMAT
Definition: mmsystem.h:176
UINT WINAPI waveInClose(HWAVEIN hWaveIn)
Definition: winmm.c:2637
unsigned int sample_rate(void) const
#define CloseHandle
Definition: compat.h:398
VOID WINAPI DECLSPEC_HOTPATCH Sleep(IN DWORD dwMilliseconds)
Definition: synch.c:736
#define error(str)
Definition: mkdosfs.c:1605
void open(void)
MMRESULT WINAPI waveInOpen(HWAVEIN *lphWaveIn, UINT uDeviceID, LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags)
Definition: winmm.c:2626
void add_buffers_to_driver_(void)
HWAVEIN wavein_handle
TW_UINT32 TW_UINT16 TW_UINT16 MSG
Definition: twain.h:1827
unsigned int bytes_received
void prep_headers_(void)
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:679
#define ZeroMemory
Definition: winbase.h:1635
UINT MMRESULT
Definition: mmsystem.h:962
const GLuint * buffers
Definition: glext.h:5916
struct tWAVEFORMATEX WAVEFORMATEX
Definition: austream.idl:23
LPSTR lpData
Definition: mmsystem.h:1014
#define _AUDIO_NAMESPACE_START_
Definition: audio_def.hpp:24
char * LPSTR
Definition: xmlstorage.h:182
unsigned short int bits(void) const
#define MM_WIM_DATA
Definition: mmsystem.h:61
UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR *lpWaveInHdr, UINT uSize)
Definition: winmm.c:2656
static DWORD WINAPI recording_procedure(LPVOID)
WAVEFORMATEX wave_format
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
GLenum GLclampf GLint i
Definition: glfuncs.h:14
#define WAVE_FORMAT_PCM
Definition: constants.h:425
unsigned int byte_rate(void) const
DWORD dwFlags
Definition: mmsystem.h:1018
WORD wBitsPerSample
Definition: audioclient.idl:45
UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR *lpWaveInHdr, UINT uSize)
Definition: winmm.c:2687
void init_(void)
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:112
smooth NULL
Definition: ftsmooth.c:416
DWORD nSamplesPerSec
Definition: audioclient.idl:42
unsigned int buffers
unsigned int block_align(void) const
unsigned int mb_size
unsigned int BOOL
Definition: ntddk_ex.h:94
#define MMSYSERR_NOERROR
Definition: mmsystem.h:96
#define MM_WIM_CLOSE
Definition: mmsystem.h:60
if(!(yy_init))
Definition: macro.lex.yy.c:717
BYTE * main_buffer
unsigned long DWORD
Definition: ntddk_ex.h:95
#define CALLBACK_THREAD
Definition: mmsystem.h:151
void close(void)
virtual void audio_receive(unsigned char *, unsigned int)=0
void alloc_buffers_mem_(unsigned int, float)
UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn, WAVEHDR *lpWaveInHdr, UINT uSize)
Definition: winmm.c:2720
DWORD dwBufferLength
Definition: mmsystem.h:1015
void start_recording(void)
#define MessageBox
Definition: winuser.h:5688
#define err(...)
HANDLE data_flushed_event
#define WINAPI
Definition: msvc.h:20
HANDLE wakeup_recthread
audio_wavein_status status
unsigned char BYTE
Definition: ntddk_ex.h:96
UINT WINAPI waveInStart(HWAVEIN hWaveIn)
Definition: winmm.c:2752
UINT WINAPI waveInReset(HWAVEIN hWaveIn)
Definition: winmm.c:2737
void unprep_headers_(void)
#define TEXT(s)
Definition: k32.h:26
UINT WINAPI waveInStop(HWAVEIN hWaveIn)
Definition: winmm.c:2767
DWORD nAvgBytesPerSec
Definition: audioclient.idl:43
audio_receiver & audio_rcvd
#define GetMessage
Definition: winuser.h:5656
WAVEHDR * wave_headers
unsigned short int channels(void) const
void stop_recording(void)
#define msg(x)
Definition: auth_time.c:54
#define _AUDIO_NAMESPACE_END_
Definition: audio_def.hpp:25
#define WHDR_DONE
Definition: mmsystem.h:193
DWORD recthread_id
#define _AUDIO_DEFAULT_WAVEINBUFSECS
Definition: audio_def.hpp:16
#define INFINITE
Definition: serial.h:102
audio_format aud_info
void init_headers_(void)
DWORD dwBytesRecorded
Definition: mmsystem.h:1016
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:29
Definition: ps.c:97