ReactOS  0.4.13-dev-99-g7e18b6d
audio_waveout.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_waveout.cpp
4  * PURPOSE: Sound recording
5  * PROGRAMMERS: Marco Pagliaricci (irc: rendar)
6  */
7 
8 #include "stdafx.h"
9 #include "audio_waveout.hpp"
10 
12 
13 void
15 {
18  waveout_handle = 0;
19  playthread_id = 0;
23 }
24 
25 void
26 audio_waveout::alloc_buffers_mem_(unsigned int buffs, float secs)
27 {
28  unsigned int onebuf_size = 0, tot_size = 0;
29 
30  /* Release old memory */
31  if (main_buffer)
32  delete[] main_buffer;
33 
34  if (wave_headers)
35  delete[] wave_headers;
36 
37  /* Calcs size of the buffers */
38  onebuf_size = (unsigned int)((float)aud_info.byte_rate() * secs);
39  tot_size = onebuf_size * buffs;
40  /* Allocs memory for the audio buffers */
41  main_buffer = new BYTE[tot_size];
42  /* Allocs memory for the `WAVEHDR' structures */
43  wave_headers = (WAVEHDR *) new BYTE[sizeof(WAVEHDR) * buffs];
44  /* Zeros memory */
45  ZeroMemory(main_buffer, tot_size);
46  ZeroMemory(wave_headers, sizeof(WAVEHDR) * buffs);
47  /* Updates total size of the buffers */
48  mb_size = tot_size;
49 }
50 
51 void
53 {
54  /* If there is no memory for memory or headers, simply return */
55  if ((!wave_headers) || (!main_buffer))
56  return;
57 
58  /* This is the size for one buffer */
59  DWORD buf_sz = mb_size / buffers;
60  /* This is the base address for one buffer */
61  BYTE *buf_addr = main_buffer;
62 
64 
65  /* Initializes headers */
66  for (unsigned int i = 0; i < buffers; ++i)
67  {
68  /* Sets the correct base address and length for the little buffer */
70  wave_headers[i].lpData = (LPSTR) buf_addr;
71 
72  /* Unsets the WHDR_DONE flag */
74 
75  /* Sets the WAVEHDR user data with an unique little buffer ID# */
76  wave_headers[i].dwUser = (unsigned int)i;
77 
78  /* Increments little buffer base address */
79  buf_addr += buf_sz;
80  }
81 }
82 
83 void
85 {
86  MMRESULT err;
87  bool error = false;
88 
89  /* If there is no memory for memory or headers, throw error */
90  if ((!wave_headers) || (!main_buffer) || (!waveout_handle))
91  {
92  /* TODO: throw error! */
93  }
94 
95  for (unsigned int i = 0; i < buffers; ++i)
96  {
98  if (err != MMSYSERR_NOERROR)
99  error = true;
100  }
101 
102  if (error)
103  {
104  /* TODO: throw error indicating which header i-th is errorneous */
105  }
106 }
107 
108 void
110 {
111  MMRESULT err;
112  bool error = false;
113 
114  /* If there is no memory for memory or headers, throw error */
115  if ((!wave_headers) || (!main_buffer) || (!waveout_handle))
116  {
117  /* TODO: throw error! */
118  }
119 
120  for (unsigned int i = 0; i < buffers; ++i)
121  {
123  if (err != MMSYSERR_NOERROR)
124  error = true;
125  }
126 
127  if (error)
128  {
129  /* TODO: throw error indicating which header i-th is errorneous */
130  }
131 }
132 
133 void
135 {
136  /* Frees memory */
137  if (main_buffer)
138  delete[] main_buffer;
139 
140  if (wave_headers)
141  delete[] wave_headers;
142 
143  main_buffer = 0;
144  wave_headers = 0;
145 }
146 
147 void
149 {
150  MMRESULT err;
151  HANDLE playthread_handle = 0;
152 
153  /* Checkin the status of the object */
154  if (status != WAVEOUT_NOTREADY)
155  {
156  /* TODO: throw error */
157  }
158 
159  /* Creating the EVENT object that will be signaled when
160  the playing thread has to wake up */
162  if (!wakeup_playthread)
163  {
165  /* TODO: throw error */
166  }
167 
168  /* Inialize buffers for recording audio data from the wavein audio line */
170  init_headers_();
171 
172  /* Sound format that will be captured by wavein */
179 
180  /* Creating the recording thread */
181  playthread_handle = CreateThread(NULL,
182  0,
184  (PVOID)this,
185  0,
186  &playthread_id);
187  /* Checking thread handle */
188  if (!playthread_handle)
189  {
190  /* Updating status */
192  /* TODO: throw error */
193  }
194 
195  /* We don't need the thread handle anymore, so we can close it from now.
196  (We'll just need the thread ID for the `waveInOpen' API) */
197  CloseHandle(playthread_handle);
198 
199  /* Reset the `audio_source' to the start position */
201  /* Opens the WAVE_OUT device */
203  WAVE_MAPPER,
204  &wave_format,
206  0,
208  if (err != MMSYSERR_NOERROR)
209  {
210  MessageBox(0, _T("waveOutOpen Error"), 0, 0);
211  /* TODO: throw error */
212  }
213 
215 }
216 
217 void
219 {
220  MMRESULT err;
221  unsigned int i;
222 
223  if (!main_buffer)
224  {
225  /* TODO; throw error, or assert */
226  return;
227  }
228 
229  /* If the status is PAUSED, we have to resume the audio playing */
230  if (status == WAVEOUT_PAUSED)
231  {
232  /* Updates status */
234  /* Tells to the driver to resume audio playing */
236  /* Wakeup playing thread */
238  return;
239  } /* if status == WAVEOUT_PAUSED */
240 
241  if (status != WAVEOUT_READY)
242  return;
243 
244  /* Prepares WAVEHDR structures */
245  prep_headers_();
246  /* Sets correct status */
248  /* Reads the audio from the start */
249  //audio_buf.set_position_start();
250 
251  /* Reads the first N bytes from the audio buffer, where N = the total
252  size of all little buffers */
254 
255  /* Wakeup the playing thread */
257 
258  /* Sends all the little buffers to the audio driver, so it can play
259  the sound data */
260  for (i = 0; i < buffers; ++i)
261  {
263  if (err != MMSYSERR_NOERROR)
264  {
265  MessageBox(0, _T("waveOutWrite Error"), 0, 0);
266  /* TODO: throw error */
267  }
268  }
269 }
270 
271 void
273 {
274  MMRESULT err;
275 
276  /* If the waveout object is not playing audio, do nothing */
277  if (status == WAVEOUT_PLAYING)
278  {
279  /* Updating status */
281  /* Tells to audio driver to pause audio */
283  if (err != MMSYSERR_NOERROR)
284  {
285  MessageBox(0, _T("waveOutPause Error"), 0, 0);
286  /* TODO: throw error */
287  }
288  }
289 }
290 
291 void
293 {
294  MMRESULT err;
295 
296  /* Checks the current status */
297  if ((status != WAVEOUT_PLAYING) &&
298  (status != WAVEOUT_FLUSHING) &&
299  (status != WAVEOUT_PAUSED))
300  {
301  /* Do nothing */
302  return;
303  }
304 
305  /* Sets a new status */
307  /* Flushes pending audio datas */
309  if (err != MMSYSERR_NOERROR)
310  {
311  MessageBox(0, _T("err WaveOutReset.\n"),_T("ERROR"), 0);
312  /* TODO: throw error */
313  }
314 
315  /* Sets the start position of the audio buffer */
317  /* Cleans little buffers */
318  unprep_headers_();
319  init_headers_();
320  /* Refreshes the status */
322 }
323 
324 void
326 {
327  MMRESULT err;
328 
329  /* If the `wave_out' object is playing audio, or it is in paused state,
330  we have to call the `stop' member function, to flush pending buffers */
332  {
333  stop();
334  }
335 
336  /* When we have flushed all pending buffers, the wave out handle can be successfully closed */
338  if (err != MMSYSERR_NOERROR)
339  {
340  MessageBox(0, _T("waveOutClose Error"), 0, 0);
341  /* TODO: throw error */
342  }
343 
345 }
346 
347 DWORD WINAPI
349 {
350  MSG msg;
351  WAVEHDR *phdr;
352  MMRESULT err;
353  audio_waveout *_this = (audio_waveout *)arg;
354  unsigned int read_size;
355 
356  /* Check the arg pointer */
357  if (_this == 0)
358  return 0;
359 
360  /* The thread can go to sleep for now. It will be wake up only when
361  there is audio data to be recorded */
362  if (_this->wakeup_playthread)
364 
365  /* Entering main polling loop */
366  while (GetMessage(&msg, 0, 0, 0))
367  {
368  switch (msg.message)
369  {
370  case MM_WOM_DONE:
371  phdr = (WAVEHDR *)msg.lParam;
372 
373  /* If the status of the `wave_out' object is different
374  than playing, then the thread can go to sleep */
375  if ((_this->status != WAVEOUT_PLAYING) &&
376  (_this->status != WAVEOUT_FLUSHING) &&
377  (_this->wakeup_playthread))
378  {
380  }
381 
382  /* The playing thread doesn't have to sleep, so let's checking
383  first if the little buffer has been sent to the audio driver
384  (it has the WHDR_DONE flag). If it is, we can read new audio
385  datas from the `audio_producer' object, refill the little buffer,
386  and resend it to the driver with waveOutWrite( ) API */
387  if (phdr->dwFlags & WHDR_DONE)
388  {
389  if (_this->status == WAVEOUT_PLAYING)
390  {
391  /* Here the thread is still playing a sound, so it can
392  read new audio data from the `audio_producer' object */
393  read_size = _this->audio_buf.read((BYTE *)phdr->lpData,
394  phdr->dwBufferLength);
395  } else
396  read_size = 0;
397 
398  /* If the `audio_producer' object, has produced some
399  audio data, so `read_size' will be > 0 */
400  if (read_size)
401  {
402  /* Adjusts the correct effectively read size */
403  phdr->dwBufferLength = read_size;
404 
405  /* Before sending the little buffer to the driver,
406  we have to remove the `WHDR_DONE' flag, because
407  the little buffer now contain new audio data that have to be played */
408  phdr->dwFlags &= ~WHDR_DONE;
409 
410  /* Plays the sound of the little buffer */
412  phdr,
413  sizeof(WAVEHDR));
414 
415  /* Checking if any error has occured */
416  if (err != MMSYSERR_NOERROR)
417  {
418  MessageBox(0, _T("waveOutWrite Error"), 0, 0);
419  /* TODO: throw error */
420  }
421  }
422  else
423  {
424  /* Here `read_size' is 0, so the `audio_producer' object,
425  doesn't have any sound data to produce anymore. So,
426  now we have to see the little buffer #ID to establishing what to do */
427  if (phdr->dwUser == 0)
428  {
429  /* Here `read_size' is 0, and the buffer user data
430  contain 0, so this is the first of N little
431  buffers that came back with `WHDR_DONE' flag;
432  this means that this is the last little buffer
433  in which we have to read data to; so we can
434  _STOP_ reading data from the `audio_producer'
435  object: doing this is accomplished just setting
436  the current status as "WAVEOUT_FLUSHING" */
437  _this->status = WAVEOUT_FLUSHING;
438  }
439  else if (phdr->dwUser == (_this->buffers - 1))
440  {
441  /* Here `read_size' and the buffer user data, that
442  contain a buffer ID#, is equal to the number of
443  the total buffers - 1. This means that this is
444  the _LAST_ little buffer that has been played by
445  the audio driver. We can STOP the `wave_out'
446  object now, or restart the sound playing, if we have a infinite loop */
447  _this->stop();
448 
449  /* Let the thread go to sleep */
450  if (_this->audio_buf.play_finished)
451  _this->audio_buf.play_finished();
452 
453  if (_this->wakeup_playthread)
455  INFINITE);
456 
457  } /* if (phdr->dwUser == (_this->buffers - 1)) */
458  } /* if read_size != 0 */
459  } /* (phdr->dwFlags & WHDR_DONE) */
460  break; /* end case */
461  case MM_WOM_CLOSE:
462  /* The thread can exit now */
463  return 0;
464  break;
465  case MM_WOM_OPEN:
466  /* Do nothing */
467  break;
468  } /* end switch(msg.message) */
469  } /* end while(GetMessage(...)) */
470 
471  return 0;
472 }
473 
#define CreateEvent
Definition: winbase.h:3562
void free_buffers_mem_(void)
void set_position_start(void)
unsigned int sample_rate(void) const
#define CloseHandle
Definition: compat.h:398
void stop(void)
#define error(str)
Definition: mkdosfs.c:1605
void open(void)
void prep_headers_(void)
#define MM_WOM_OPEN
Definition: mmsystem.h:56
TW_UINT32 TW_UINT16 TW_UINT16 MSG
Definition: twain.h:1827
#define WAVE_ALLOWSYNC
Definition: mmsystem.h:189
static DWORD WINAPI playing_procedure(LPVOID)
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
audio_producer & audio_buf
#define MM_WOM_DONE
Definition: mmsystem.h:58
WAVEFORMATEX wave_format
HWAVEOUT waveout_handle
#define _AUDIO_DEFAULT_WAVEOUTBUFSECS
Definition: audio_def.hpp:19
UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut, WAVEHDR *lpWaveOutHdr, UINT uSize)
Definition: winmm.c:2280
void play(void)
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
DWORD dwFlags
Definition: mmsystem.h:1018
void unprep_headers_(void)
WORD wBitsPerSample
Definition: audioclient.idl:45
unsigned int buffers
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 block_align(void) const
#define _T(x)
Definition: vfdio.h:22
#define MMSYSERR_NOERROR
Definition: mmsystem.h:96
#define WAVE_MAPPER
Definition: mmsystem.h:187
#define MM_WOM_CLOSE
Definition: mmsystem.h:57
if(!(yy_init))
Definition: macro.lex.yy.c:714
UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
Definition: winmm.c:2374
virtual unsigned int read(BYTE *, unsigned int)=0
#define WINAPI
Definition: msvc.h:8
audio_waveout_status status
unsigned long DWORD
Definition: ntddk_ex.h:95
#define CALLBACK_THREAD
Definition: mmsystem.h:151
unsigned int mb_size
UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr, UINT uSize)
Definition: winmm.c:2344
void close(void)
const audio_format & aud_info
DWORD dwBufferLength
Definition: mmsystem.h:1015
void init_headers_(void)
WAVEHDR * wave_headers
unsigned char BYTE
Definition: mem.h:68
#define MessageBox
Definition: winuser.h:5688
#define err(...)
UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr, UINT uSize)
Definition: winmm.c:2310
MMRESULT WINAPI waveOutOpen(LPHWAVEOUT lphWaveOut, UINT uDeviceID, LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags)
Definition: winmm.c:2249
DWORD nAvgBytesPerSec
Definition: audioclient.idl:43
UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
Definition: winmm.c:2260
#define GetMessage
Definition: winuser.h:5656
DWORD_PTR dwUser
Definition: mmsystem.h:1017
unsigned short int channels(void) const
void alloc_buffers_mem_(unsigned int, float)
UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
Definition: winmm.c:2402
#define msg(x)
Definition: auth_time.c:54
#define _AUDIO_NAMESPACE_END_
Definition: audio_def.hpp:25
void pause(void)
#define WHDR_DONE
Definition: mmsystem.h:193
#define INFINITE
Definition: serial.h:102
HANDLE wakeup_playthread
UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
Definition: winmm.c:2388
void init_(void)
void(* play_finished)(void)
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
Definition: ps.c:97