ReactOS  0.4.12-dev-36-g472787f
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 {
17  wave_format.cbSize = sizeof(WAVEFORMATEX);
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  {
262  err = waveOutWrite(waveout_handle, &wave_headers[i], sizeof(WAVEHDR));
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 */
308  err = waveOutReset( waveout_handle );
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 */
411  err = waveOutWrite(_this->waveout_handle,
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
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
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:717
UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
Definition: winmm.c:2374
virtual unsigned int read(BYTE *, unsigned int)=0
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
#define MessageBox
Definition: winuser.h:5688
#define err(...)
UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr, UINT uSize)
Definition: winmm.c:2310
#define WINAPI
Definition: msvc.h:20
unsigned char BYTE
Definition: ntddk_ex.h:96
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:29
Definition: ps.c:97