ReactOS 0.4.15-dev-8428-g6910fa6
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
13void
15{
19 playthread_id = 0;
23}
24
25void
26audio_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
51void
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 */
73 wave_headers[i].dwFlags &= ~WHDR_DONE;
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
83void
85{
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
108void
110{
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
133void
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
147void
149{
151 HANDLE playthread_handle = 0;
152
153 /* Checkin the status of the object */
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 */
163 {
165 /* TODO: throw error */
166 }
167
168 /* Inialize buffers for recording audio data from the wavein audio line */
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,
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 */
206 0,
208 if (err != MMSYSERR_NOERROR)
209 {
210 MessageBox(0, _T("waveOutOpen Error"), 0, 0);
211 /* TODO: throw error */
212 }
213
215}
216
217void
219{
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 */
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
271void
273{
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
291void
293{
295
296 /* Checks the current status */
297 if ((status != WAVEOUT_PLAYING) &&
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 */
320 /* Refreshes the status */
322}
323
324void
326{
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
349{
350 MSG msg;
351 WAVEHDR *phdr;
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 _AUDIO_NAMESPACE_START_
Definition: audio_def.hpp:24
#define _AUDIO_DEFAULT_WAVEOUTBUFSECS
Definition: audio_def.hpp:19
#define _AUDIO_NAMESPACE_END_
Definition: audio_def.hpp:25
@ WAVEOUT_NOTREADY
@ WAVEOUT_PAUSED
@ WAVEOUT_PLAYING
@ WAVEOUT_ERR
@ WAVEOUT_FLUSHING
@ WAVEOUT_STOP
@ WAVEOUT_READY
#define msg(x)
Definition: auth_time.c:54
#define WAVE_FORMAT_PCM
Definition: constants.h:425
unsigned short int bits(void) const
unsigned int byte_rate(void) const
unsigned int sample_rate(void) const
unsigned short int channels(void) const
unsigned int block_align(void) const
virtual unsigned int read(BYTE *, unsigned int)=0
void(* play_finished)(void)
void set_position_start(void)
HANDLE wakeup_playthread
void play(void)
static DWORD WINAPI playing_procedure(LPVOID)
unsigned int mb_size
void stop(void)
WAVEHDR * wave_headers
audio_producer & audio_buf
void open(void)
void init_(void)
void init_headers_(void)
void alloc_buffers_mem_(unsigned int, float)
const audio_format & aud_info
unsigned int buffers
void close(void)
void unprep_headers_(void)
void prep_headers_(void)
void free_buffers_mem_(void)
WAVEFORMATEX wave_format
void pause(void)
audio_waveout_status status
HWAVEOUT waveout_handle
#define NULL
Definition: types.h:112
#define FALSE
Definition: types.h:117
#define CloseHandle
Definition: compat.h:739
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:137
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
#define INFINITE
Definition: serial.h:102
unsigned long DWORD
Definition: ntddk_ex.h:95
const GLuint * buffers
Definition: glext.h:5916
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
if(dx< 0)
Definition: linetemp.h:194
#define error(str)
Definition: mkdosfs.c:1605
UINT MMRESULT
Definition: mmsystem.h:962
#define CALLBACK_THREAD
Definition: mmsystem.h:151
#define MM_WOM_CLOSE
Definition: mmsystem.h:57
#define MM_WOM_OPEN
Definition: mmsystem.h:56
#define WAVE_ALLOWSYNC
Definition: mmsystem.h:189
#define WAVE_MAPPER
Definition: mmsystem.h:187
#define MM_WOM_DONE
Definition: mmsystem.h:58
#define MMSYSERR_NOERROR
Definition: mmsystem.h:96
#define WHDR_DONE
Definition: mmsystem.h:193
#define err(...)
DWORD nAvgBytesPerSec
Definition: audioclient.idl:43
WORD wBitsPerSample
Definition: audioclient.idl:45
DWORD nSamplesPerSec
Definition: audioclient.idl:42
Definition: ps.c:97
DWORD dwBufferLength
Definition: mmsystem.h:1015
DWORD dwFlags
Definition: mmsystem.h:1018
DWORD_PTR dwUser
Definition: mmsystem.h:1017
LPSTR lpData
Definition: mmsystem.h:1014
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:733
TW_UINT32 TW_UINT16 TW_UINT16 MSG
Definition: twain.h:1829
#define _T(x)
Definition: vfdio.h:22
#define ZeroMemory
Definition: winbase.h:1712
#define CreateEvent
Definition: winbase.h:3748
#define WINAPI
Definition: msvc.h:6
UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
Definition: winmm.c:2385
UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr, UINT uSize)
Definition: winmm.c:2341
UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr, UINT uSize)
Definition: winmm.c:2307
MMRESULT WINAPI waveOutOpen(LPHWAVEOUT lphWaveOut, UINT uDeviceID, LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags)
Definition: winmm.c:2246
UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
Definition: winmm.c:2399
UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut, WAVEHDR *lpWaveOutHdr, UINT uSize)
Definition: winmm.c:2277
UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
Definition: winmm.c:2371
UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
Definition: winmm.c:2257
#define GetMessage
Definition: winuser.h:5799
#define MessageBox
Definition: winuser.h:5831
char * LPSTR
Definition: xmlstorage.h:182
unsigned char BYTE
Definition: xxhash.c:193