ReactOS  0.4.13-dev-100-gc8611ae
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 {
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 */
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 */
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 */
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 */
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
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define WAVE_FORMAT_PCM
Definition: constants.h:425
unsigned int byte_rate(void) const
unsigned int BOOL
Definition: ntddk_ex.h:94
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
#define MMSYSERR_NOERROR
Definition: mmsystem.h:96
#define MM_WIM_CLOSE
Definition: mmsystem.h:60
if(!(yy_init))
Definition: macro.lex.yy.c:714
BYTE * main_buffer
#define WINAPI
Definition: msvc.h:8
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)
unsigned char BYTE
Definition: mem.h:68
#define MessageBox
Definition: winuser.h:5688
#define err(...)
HANDLE data_flushed_event
HANDLE wakeup_recthread
audio_wavein_status status
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:31
Definition: ps.c:97