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)
11 #include "audio_wavein.hpp"
15 _AUDIO_NAMESPACE_START_
19 audio_wavein::init_( void )
21 ZeroMemory(( LPVOID
) &wave_format
,
22 sizeof( WAVEFORMATEX
));
24 wave_format
.cbSize
= sizeof( WAVEFORMATEX
);
30 data_flushed_event
= 0;
32 buf_secs
= _AUDIO_DEFAULT_WAVEINBUFSECS
;
35 status
= WAVEIN_NOTREADY
;
40 audio_wavein::alloc_buffers_mem_( unsigned int buffs
, float secs
)
45 onebuf_size
= 0, tot_size
= 0;
57 delete[] wave_headers
;
62 // Calcs size of the buffers
65 onebuf_size
= ( unsigned int )
66 (( float )aud_info
.byte_rate() * secs
);
69 tot_size
= onebuf_size
* buffs
;
75 // Allocs memory for the audio buffers
78 main_buffer
= new BYTE
[ tot_size
];
83 // Allocs memory for the `WAVEHDR' structures.
86 wave_headers
= ( WAVEHDR
* )
87 new BYTE
[ sizeof( WAVEHDR
) * buffs
];
95 ZeroMemory( main_buffer
, tot_size
);
97 ZeroMemory( wave_headers
,
98 sizeof( WAVEHDR
) * buffs
);
102 // Updates total size of the buffers.
111 audio_wavein::free_buffers_mem_( void )
120 delete[] main_buffer
;
124 delete[] wave_headers
;
134 audio_wavein::init_headers_( void )
140 // If there is no memory for memory or
141 // headers, simply return.
144 if (( !wave_headers
) || ( !main_buffer
))
149 // This is the size for one buffer
152 DWORD buf_sz
= mb_size
/ buffers
;
157 // This is the base address for one buffer
160 BYTE
* buf_addr
= main_buffer
;
164 // Initializes headers.
167 for ( unsigned int i
= 0; i
< buffers
; ++i
)
169 wave_headers
[ i
].dwBufferLength
= mb_size
/ buffers
;
170 wave_headers
[ i
].lpData
= ( LPSTR
) buf_addr
;
179 audio_wavein::prep_headers_( void )
186 // If there is no memory for memory or
187 // headers, throw error.
190 if (( !wave_headers
)
191 || ( !main_buffer
) || ( !wavein_handle
))
192 {} //TODO: throw error!
196 for ( unsigned int i
= 0; i
< buffers
; ++i
)
198 err
= waveInPrepareHeader( wavein_handle
,
199 &wave_headers
[ i
], sizeof( WAVEHDR
));
202 if ( err
!= MMSYSERR_NOERROR
)
209 MessageBox( 0, TEXT("waveInPrepareHeader Error."), 0, 0 );
216 audio_wavein::unprep_headers_( void )
224 // If there is no memory for memory or
225 // headers, throw error.
228 if (( !wave_headers
)
229 || ( !main_buffer
) || ( !wavein_handle
))
230 {} //TODO: throw error!
234 for ( unsigned int i
= 0; i
< buffers
; ++i
)
236 err
= waveInUnprepareHeader( wavein_handle
,
237 &wave_headers
[ i
], sizeof( WAVEHDR
));
240 if ( err
!= MMSYSERR_NOERROR
)
247 MessageBox( 0, TEXT("waveInUnPrepareHeader Error."), 0, 0 );
253 audio_wavein::add_buffers_to_driver_( void )
261 // If there is no memory for memory or
262 // headers, throw error.
265 if (( !wave_headers
)
266 || ( !main_buffer
) || ( !wavein_handle
))
267 {} //TODO: throw error!
272 for ( unsigned int i
= 0; i
< buffers
; ++i
)
274 err
= waveInAddBuffer( wavein_handle
,
275 &wave_headers
[ i
], sizeof( WAVEHDR
));
278 if ( err
!= MMSYSERR_NOERROR
)
285 MessageBox( 0, TEXT("waveInAddBuffer Error."), 0, 0 );
292 audio_wavein::close( void )
299 // If wavein object is already in the status
300 // NOTREADY, nothing to do.
303 if ( status
== WAVEIN_NOTREADY
)
309 // If the wavein is recording,
310 // then stop recording and close it.
313 if ( status
== WAVEIN_RECORDING
)
321 status
= WAVEIN_NOTREADY
;
327 // Wakeing up recording thread, so it
328 // can receive the `MM_WIM_CLOSE' message
331 if ( wakeup_recthread
)
332 SetEvent( wakeup_recthread
);
337 // Closing wavein stream
340 while (( waveInClose( wavein_handle
))
341 != MMSYSERR_NOERROR
) Sleep( 1 );
346 // Release buffers memory.
353 // Re-initialize variables to the
363 audio_wavein::open( void )
367 HANDLE recthread_handle
= 0;
371 // Checkin the status of the object
374 if ( status
!= WAVEIN_NOTREADY
)
375 {} //TODO: throw error
380 // Creating the EVENT object that will be signaled
381 // when the recording thread has to wake up.
385 CreateEvent( 0, FALSE
, FALSE
, 0 );
389 CreateEvent( 0, FALSE
, FALSE
, 0 );
393 if (( !wakeup_recthread
) || ( !data_flushed_event
))
399 MessageBox( 0, TEXT("Thread Error."), 0, 0 );
407 // Inialize buffers for recording audio
408 // data from the wavein audio line.
411 alloc_buffers_mem_( buffers
, buf_secs
);
420 // Sound format that will be captured by wavein
423 wave_format
.wFormatTag
= WAVE_FORMAT_PCM
;
425 wave_format
.nChannels
= aud_info
.channels();
426 wave_format
.nSamplesPerSec
= aud_info
.sample_rate();
427 wave_format
.wBitsPerSample
= aud_info
.bits();
428 wave_format
.nBlockAlign
= aud_info
.block_align();
429 wave_format
.nAvgBytesPerSec
= aud_info
.byte_rate();
434 // Creating the recording thread
440 audio_wavein::recording_procedure
,
449 // Checking thread handle
452 if ( !recthread_handle
)
461 MessageBox( 0, TEXT("Thread Error."), 0, 0 );
468 // We don't need the thread handle anymore,
469 // so we can close it from now. (We'll just
470 // need the thread ID for the `waveInOpen' API)
473 CloseHandle( recthread_handle
);
478 // Opening audio line wavein
481 err
= waveInOpen( &wavein_handle
,
490 if ( err
!= MMSYSERR_NOERROR
)
500 if ( err
== WAVERR_BADFORMAT
)
501 MessageBox( 0, TEXT("waveInOpen Error"), 0, 0 );
509 // Update object status
512 status
= WAVEIN_READY
;
517 // Now `audio_wavein' object is ready
518 // for audio recording!
525 audio_wavein::start_recording( void )
533 if (( status
!= WAVEIN_READY
)
534 && ( status
!= WAVEIN_STOP
))
535 {} //TODO: throw error
541 // Updating to the recording status
544 status
= WAVEIN_RECORDING
;
550 // Let's prepare header of type WAVEHDR that
551 // we will pass to the driver with our
552 // audio informations, and buffer informations.
560 // The waveInAddBuffer function sends an input buffer
561 // to the given waveform-audio input device.
562 // When the buffer is filled, the application is notified.
565 add_buffers_to_driver_();
572 // Signaling event for waking up
573 // the recorder thread.
576 ev
= SetEvent( wakeup_recthread
);
583 MessageBox( 0, TEXT("Event Error."), 0, 0 );
593 err
= waveInStart( wavein_handle
);
596 if ( err
!= MMSYSERR_NOERROR
)
605 MessageBox( 0, TEXT("waveInStart Error."), 0, 0 );
617 audio_wavein::stop_recording( void )
625 if ( status
!= WAVEIN_RECORDING
)
630 status
= WAVEIN_FLUSHING
;
634 // waveInReset will make all pending buffer as done.
637 err
= waveInReset( wavein_handle
);
640 if ( err
!= MMSYSERR_NOERROR
)
645 MessageBox( 0, TEXT("waveInReset Error."), 0, 0 );
652 if ( data_flushed_event
)
653 wait
= WaitForSingleObject(
654 data_flushed_event
, INFINITE
667 err
= waveInStop( wavein_handle
);
670 if ( err
!= MMSYSERR_NOERROR
)
675 MessageBox( 0, TEXT("waveInStop Error."), 0, 0 );
683 // The waveInUnprepareHeader function cleans up the
684 // preparation performed by the waveInPrepareHeader function.
699 status
= WAVEIN_STOP
;
706 audio_wavein::recording_procedure( LPVOID arg
)
713 audio_wavein
* _this
= ( audio_wavein
* ) arg
;
719 // Check the arg pointer
728 // The thread can go to sleep for now.
729 // It will be wake up only when there is audio data
733 if ( _this
->wakeup_recthread
)
734 wait
= WaitForSingleObject(
735 _this
->wakeup_recthread
, INFINITE
744 // If status of the `audio_wavein' object
745 // is not ready or recording the thread can exit.
748 if (( _this
->status
!= WAVEIN_READY
) &&
749 ( _this
->status
!= WAVEIN_RECORDING
))
759 // Entering main polling loop
762 while ( GetMessage( &msg
, 0, 0, 0 ))
765 switch ( msg
.message
)
770 phdr
= ( WAVEHDR
* ) msg
.lParam
;
772 if (( _this
->status
== WAVEIN_RECORDING
)
773 || ( _this
->status
== WAVEIN_FLUSHING
))
777 if ( phdr
->dwFlags
& WHDR_DONE
)
781 // Flushes recorded audio data to
782 // the `audio_receiver' object.
785 _this
->audio_rcvd
.audio_receive(
786 ( unsigned char * )phdr
->lpData
,
787 phdr
->dwBytesRecorded
792 // Updating `audio_receiver' total
793 // bytes received _AFTER_ calling
794 // `audio_receive' function.
797 _this
->audio_rcvd
.bytes_received
+=
798 phdr
->dwBytesRecorded
;
804 // If status is not flushing data, then
805 // we can re-add the buffer for reusing it.
806 // Otherwise, if we are flushing pending data,
807 // we cannot re-add buffer because we don't need
811 if ( _this
->status
!= WAVEIN_FLUSHING
)
815 // Let the audio driver reuse the buffer
818 waveInAddBuffer( _this
->wavein_handle
,
819 phdr
, sizeof( WAVEHDR
));
825 // If we are flushing pending data, we have
826 // to prepare to stop recording.
827 // Set WAVEHDR flag to 0, and fires the event
828 // `data_flushed_event', that will wake up
829 // the main thread that is sleeping into
830 // wavein_in::stop_recording() member function,
831 // waiting the last `MM_WIM_DATA' message that
832 // contain pending data.
837 SetEvent( _this
->data_flushed_event
);
841 // The recording is gooing to stop, so the
842 // recording thread can go to sleep!
845 wait
= WaitForSingleObject(
846 _this
->wakeup_recthread
, INFINITE
);
851 }//if WAVEIN_RECORDING || WAVEIN_FLUSHING
866 // The thread can exit now.
875 } //end switch( msg.message )
877 } //end while( GetMessage( ... ))
887 _AUDIO_NAMESPACE_END_