2 * PROJECT: ReactOS Sound Record Application
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/sndrec32/audio_wavein.cpp
5 * PURPOSE: Audio WaveIn
6 * PROGRAMMERS: Marco Pagliaricci <ms_blue (at) hotmail (dot) it>
10 #include "audio_wavein.hpp"
14 _AUDIO_NAMESPACE_START_
18 audio_wavein::init_( void )
20 ZeroMemory(( LPVOID
) &wave_format
,
21 sizeof( WAVEFORMATEX
));
23 wave_format
.cbSize
= sizeof( WAVEFORMATEX
);
29 buf_secs
= _AUDIO_DEFAULT_WAVEINBUFSECS
;
32 status
= WAVEIN_NOTREADY
;
37 audio_wavein::alloc_buffers_mem_( unsigned int buffs
, float secs
)
42 onebuf_size
= 0, tot_size
= 0;
54 delete[] wave_headers
;
59 // Calcs size of the buffers
62 onebuf_size
= ( unsigned int )
63 (( float )aud_info
.byte_rate() * secs
);
66 tot_size
= onebuf_size
* buffs
;
72 // Allocs memory for the audio buffers
75 main_buffer
= new BYTE
[ tot_size
];
80 // Allocs memory for the `WAVEHDR' structures.
83 wave_headers
= ( WAVEHDR
* )
84 new BYTE
[ sizeof( WAVEHDR
) * buffs
];
92 ZeroMemory( main_buffer
, tot_size
);
94 ZeroMemory( wave_headers
,
95 sizeof( WAVEHDR
) * buffs
);
99 // Updates total size of the buffers.
108 audio_wavein::free_buffers_mem_( void )
117 delete[] main_buffer
;
121 delete[] wave_headers
;
131 audio_wavein::init_headers_( void )
137 // If there is no memory for memory or
138 // headers, simply return.
141 if (( !wave_headers
) || ( !main_buffer
))
146 // This is the size for one buffer
149 DWORD buf_sz
= mb_size
/ buffers
;
154 // This is the base address for one buffer
157 BYTE
* buf_addr
= main_buffer
;
161 // Initializes headers.
164 for ( unsigned int i
= 0; i
< buffers
; ++i
)
166 wave_headers
[ i
].dwBufferLength
= mb_size
/ buffers
;
167 wave_headers
[ i
].lpData
= ( LPSTR
) buf_addr
;
176 audio_wavein::prep_headers_( void )
183 // If there is no memory for memory or
184 // headers, throw error.
187 if (( !wave_headers
)
188 || ( !main_buffer
) || ( !wavein_handle
))
189 {} //TODO: throw error!
193 for ( unsigned int i
= 0; i
< buffers
; ++i
)
195 err
= waveInPrepareHeader( wavein_handle
,
196 &wave_headers
[ i
], sizeof( WAVEHDR
));
199 if ( err
!= MMSYSERR_NOERROR
)
206 MessageBox( 0, TEXT("waveInPrepareHeader Error."), 0, 0 );
213 audio_wavein::unprep_headers_( void )
221 // If there is no memory for memory or
222 // headers, throw error.
225 if (( !wave_headers
)
226 || ( !main_buffer
) || ( !wavein_handle
))
227 {} //TODO: throw error!
231 for ( unsigned int i
= 0; i
< buffers
; ++i
)
233 err
= waveInUnprepareHeader( wavein_handle
,
234 &wave_headers
[ i
], sizeof( WAVEHDR
));
237 if ( err
!= MMSYSERR_NOERROR
)
244 MessageBox( 0, TEXT("waveInUnPrepareHeader Error."), 0, 0 );
250 audio_wavein::add_buffers_to_driver_( void )
258 // If there is no memory for memory or
259 // headers, throw error.
262 if (( !wave_headers
)
263 || ( !main_buffer
) || ( !wavein_handle
))
264 {} //TODO: throw error!
269 for ( unsigned int i
= 0; i
< buffers
; ++i
)
271 err
= waveInAddBuffer( wavein_handle
,
272 &wave_headers
[ i
], sizeof( WAVEHDR
));
275 if ( err
!= MMSYSERR_NOERROR
)
282 MessageBox( 0, TEXT("waveInAddBuffer Error."), 0, 0 );
289 audio_wavein::close( void )
296 // If wavein object is already in the status
297 // NOTREADY, nothing to do.
300 if ( status
== WAVEIN_NOTREADY
)
306 // If the wavein is recording,
307 // then stop recording and close it.
310 if ( status
== WAVEIN_RECORDING
)
318 status
= WAVEIN_NOTREADY
;
324 // Wakeing up recording thread, so it
325 // can receive the `MM_WIM_CLOSE' message
328 if ( wakeup_recthread
)
329 SetEvent( wakeup_recthread
);
334 // Closing wavein stream
337 while (( waveInClose( wavein_handle
))
338 != MMSYSERR_NOERROR
) Sleep( 1 );
343 // Release buffers memory.
350 // Re-initialize variables to the
360 audio_wavein::open( void )
364 HANDLE recthread_handle
= 0;
368 // Checkin the status of the object
371 if ( status
!= WAVEIN_NOTREADY
)
372 {} //TODO: throw error
377 // Creating the EVENT object that will be signaled
378 // when the recording thread has to wake up.
382 CreateEvent( 0, FALSE
, FALSE
, 0 );
386 CreateEvent( 0, FALSE
, FALSE
, 0 );
390 if (( !wakeup_recthread
) || ( !data_flushed_event
))
396 MessageBox( 0, TEXT("Thread Error."), 0, 0 );
404 // Inialize buffers for recording audio
405 // data from the wavein audio line.
408 alloc_buffers_mem_( buffers
, buf_secs
);
417 // Sound format that will be captured by wavein
420 wave_format
.wFormatTag
= WAVE_FORMAT_PCM
;
422 wave_format
.nChannels
= aud_info
.channels();
423 wave_format
.nSamplesPerSec
= aud_info
.sample_rate();
424 wave_format
.wBitsPerSample
= aud_info
.bits();
425 wave_format
.nBlockAlign
= aud_info
.block_align();
426 wave_format
.nAvgBytesPerSec
= aud_info
.byte_rate();
431 // Creating the recording thread
437 audio_wavein::recording_procedure
,
446 // Checking thread handle
449 if ( !recthread_handle
)
458 MessageBox( 0, TEXT("Thread Error."), 0, 0 );
465 // We don't need the thread handle anymore,
466 // so we can close it from now. (We'll just
467 // need the thread ID for the `waveInOpen' API)
470 CloseHandle( recthread_handle
);
475 // Opening audio line wavein
478 err
= waveInOpen( &wavein_handle
,
487 if ( err
!= MMSYSERR_NOERROR
)
497 if ( err
== WAVERR_BADFORMAT
)
498 MessageBox( 0, TEXT("waveInOpen Error"), 0, 0 );
506 // Update object status
509 status
= WAVEIN_READY
;
514 // Now `audio_wavein' object is ready
515 // for audio recording!
522 audio_wavein::start_recording( void )
530 if (( status
!= WAVEIN_READY
)
531 && ( status
!= WAVEIN_STOP
))
532 {} //TODO: throw error
538 // Updating to the recording status
541 status
= WAVEIN_RECORDING
;
547 // Let's prepare header of type WAVEHDR that
548 // we will pass to the driver with our
549 // audio informations, and buffer informations.
557 // The waveInAddBuffer function sends an input buffer
558 // to the given waveform-audio input device.
559 // When the buffer is filled, the application is notified.
562 add_buffers_to_driver_();
569 // Signaling event for waking up
570 // the recorder thread.
573 ev
= SetEvent( wakeup_recthread
);
580 MessageBox( 0, TEXT("Event Error."), 0, 0 );
590 err
= waveInStart( wavein_handle
);
593 if ( err
!= MMSYSERR_NOERROR
)
602 MessageBox( 0, TEXT("waveInStart Error."), 0, 0 );
614 audio_wavein::stop_recording( void )
622 if ( status
!= WAVEIN_RECORDING
)
627 status
= WAVEIN_FLUSHING
;
630 if ( data_flushed_event
)
631 wait
= WaitForSingleObject(
632 data_flushed_event
, INFINITE
638 // waveInReset will make all pending buffer as done.
641 err
= waveInReset( wavein_handle
);
644 if ( err
!= MMSYSERR_NOERROR
)
649 MessageBox( 0, TEXT("waveInReset Error."), 0, 0 );
661 err
= waveInStop( wavein_handle
);
664 if ( err
!= MMSYSERR_NOERROR
)
669 MessageBox( 0, TEXT("waveInStop Error."), 0, 0 );
677 // The waveInUnprepareHeader function cleans up the
678 // preparation performed by the waveInPrepareHeader function.
693 status
= WAVEIN_STOP
;
700 audio_wavein::recording_procedure( LPVOID arg
)
707 audio_wavein
* _this
= ( audio_wavein
* ) arg
;
713 // Check the arg pointer
722 // The thread can go to sleep for now.
723 // It will be wake up only when there is audio data
727 if ( _this
->wakeup_recthread
)
728 wait
= WaitForSingleObject(
729 _this
->wakeup_recthread
, INFINITE
738 // If status of the `audio_wavein' object
739 // is not ready or recording the thread can exit.
742 if (( _this
->status
!= WAVEIN_READY
) &&
743 ( _this
->status
!= WAVEIN_RECORDING
))
753 // Entering main polling loop
756 while ( GetMessage( &msg
, 0, 0, 0 ))
759 switch ( msg
.message
)
764 phdr
= ( WAVEHDR
* ) msg
.lParam
;
766 if (( _this
->status
== WAVEIN_RECORDING
)
767 || ( _this
->status
== WAVEIN_FLUSHING
))
771 // Flushes recorded audio data to
772 // the `audio_receiver' object.
775 _this
->audio_rcvd
.audio_receive(
776 ( unsigned char * )phdr
->lpData
,
777 phdr
->dwBytesRecorded
782 // Updating `audio_receiver' total
783 // bytes received _AFTER_ calling
784 // `audio_receive' function.
787 _this
->audio_rcvd
.bytes_received
+=
788 phdr
->dwBytesRecorded
;
794 // If status is not flushing data, then
795 // we can re-add the buffer for reusing it.
796 // Otherwise, if we are flushing pending data,
797 // we cannot re-add buffer because we don't need
801 if ( _this
->status
!= WAVEIN_FLUSHING
)
805 // Let the audio driver reuse the buffer
808 waveInAddBuffer( _this
->wavein_handle
,
809 phdr
, sizeof( WAVEHDR
));
815 // If we are flushing pending data, we have
816 // to prepare to stop recording.
817 // Set WAVEHDR flag to 0, and fires the event
818 // `data_flushed_event', that will wake up
819 // the main thread that is sleeping into
820 // wavein_in::stop_recording() member function,
821 // waiting the last `MM_WIM_DATA' message that
822 // contain pending data.
830 SetEvent( _this
->data_flushed_event
);
834 // The recording is gooing to stop, so the
835 // recording thread can go to sleep!
838 wait
= WaitForSingleObject(
839 _this
->wakeup_recthread
, INFINITE
);
844 }//if WAVEIN_RECORDING || WAVEIN_FLUSHING
859 // The thread can exit now.
868 } //end switch( msg.message )
870 } //end while( GetMessage( ... ))
880 _AUDIO_NAMESPACE_END_