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)
11 #include "audio_waveout.hpp"
14 _AUDIO_NAMESPACE_START_
19 audio_waveout::init_( void )
22 ZeroMemory(( LPVOID
) &wave_format
,
23 sizeof( WAVEFORMATEX
));
25 wave_format
.cbSize
= sizeof( WAVEFORMATEX
);
30 wakeup_playthread
= 0;
32 buf_secs
= _AUDIO_DEFAULT_WAVEOUTBUFSECS
;
35 status
= WAVEOUT_NOTREADY
;
43 audio_waveout::alloc_buffers_mem_( unsigned int buffs
, float secs
)
48 onebuf_size
= 0, tot_size
= 0;
60 delete[] wave_headers
;
65 // Calcs size of the buffers
68 onebuf_size
= ( unsigned int )
69 (( float )aud_info
.byte_rate() * secs
);
72 tot_size
= onebuf_size
* buffs
;
78 // Allocs memory for the audio buffers
81 main_buffer
= new BYTE
[ tot_size
];
86 // Allocs memory for the `WAVEHDR' structures.
89 wave_headers
= ( WAVEHDR
* )
90 new BYTE
[ sizeof( WAVEHDR
) * buffs
];
98 ZeroMemory( main_buffer
, tot_size
);
100 ZeroMemory( wave_headers
,
101 sizeof( WAVEHDR
) * buffs
);
105 // Updates total size of the buffers.
113 audio_waveout::init_headers_( void )
119 // If there is no memory for memory or
120 // headers, simply return.
123 if (( !wave_headers
) || ( !main_buffer
))
128 // This is the size for one buffer
131 DWORD buf_sz
= mb_size
/ buffers
;
136 // This is the base address for one buffer
139 BYTE
* buf_addr
= main_buffer
;
143 ZeroMemory( wave_headers
, sizeof( WAVEHDR
) * buffers
);
147 // Initializes headers.
150 for ( unsigned int i
= 0; i
< buffers
; ++i
)
154 // Sets the correct base address and
155 // lenght for the little buffer.
158 wave_headers
[ i
].dwBufferLength
= mb_size
/ buffers
;
159 wave_headers
[ i
].lpData
= ( LPSTR
) buf_addr
;
162 // Unsets the WHDR_DONE flag.
165 wave_headers
[ i
].dwFlags
&= ~WHDR_DONE
;
170 // Sets the WAVEHDR user data with an
171 // unique little buffer ID#
174 wave_headers
[ i
].dwUser
= ( unsigned int ) i
;
179 // Increments little buffer base address.
189 audio_waveout::prep_headers_( void )
196 // If there is no memory for memory or
197 // headers, throw error.
200 if (( !wave_headers
)
201 || ( !main_buffer
) || ( !waveout_handle
))
202 {} //TODO: throw error!
206 for ( unsigned int i
= 0; i
< buffers
; ++i
)
208 err
= waveOutPrepareHeader( waveout_handle
,
209 &wave_headers
[ i
], sizeof( WAVEHDR
));
212 if ( err
!= MMSYSERR_NOERROR
)
219 {} //TODO: throw error indicating which
220 //header i-th is errorneous
227 audio_waveout::unprep_headers_( void )
235 // If there is no memory for memory or
236 // headers, throw error.
239 if (( !wave_headers
)
240 || ( !main_buffer
) || ( !waveout_handle
))
241 {} //TODO: throw error!
245 for ( unsigned int i
= 0; i
< buffers
; ++i
)
247 err
= waveOutUnprepareHeader( waveout_handle
,
248 &wave_headers
[ i
], sizeof( WAVEHDR
));
251 if ( err
!= MMSYSERR_NOERROR
)
258 {} //TODO: throw error indicating which
259 //header i-th is errorneous
272 audio_waveout::free_buffers_mem_( void )
282 delete[] main_buffer
;
286 delete[] wave_headers
;
311 audio_waveout::open( void )
315 HANDLE playthread_handle
= 0;
319 // Checkin the status of the object
322 if ( status
!= WAVEOUT_NOTREADY
)
323 {} //TODO: throw error
327 // Creating the EVENT object that will be signaled
328 // when the playing thread has to wake up.
332 CreateEvent( 0, FALSE
, FALSE
, 0 );
334 if ( !wakeup_playthread
)
338 status
= WAVEOUT_ERR
;
346 // Inialize buffers for recording audio
347 // data from the wavein audio line.
350 alloc_buffers_mem_( buffers
, buf_secs
);
359 // Sound format that will be captured by wavein
362 wave_format
.wFormatTag
= WAVE_FORMAT_PCM
;
364 wave_format
.nChannels
= aud_info
.channels();
365 wave_format
.nSamplesPerSec
= aud_info
.sample_rate();
366 wave_format
.wBitsPerSample
= aud_info
.bits();
367 wave_format
.nBlockAlign
= aud_info
.block_align();
368 wave_format
.nAvgBytesPerSec
= aud_info
.byte_rate();
373 // Creating the recording thread
379 audio_waveout::playing_procedure
,
388 // Checking thread handle
391 if ( !playthread_handle
)
398 status
= WAVEOUT_ERR
;
405 // We don't need the thread handle anymore,
406 // so we can close it from now. (We'll just
407 // need the thread ID for the `waveInOpen' API)
410 CloseHandle( playthread_handle
);
415 // Reset the `audio_source' to the start
419 audio_buf
.set_position_start();
425 // Opens the WAVE_OUT device.
434 CALLBACK_THREAD
| WAVE_ALLOWSYNC
439 if ( err
!= MMSYSERR_NOERROR
)
441 MessageBox(0, _T("waveOutOpen Error"), 0, 0);
449 status
= WAVEOUT_READY
;
457 audio_waveout::play( void )
465 { return; } //TODO; throw error, or assert
471 // If the status is PAUSED, we have to
472 // resume the audio playing.
474 if ( status
== WAVEOUT_PAUSED
)
481 status
= WAVEOUT_PLAYING
;
485 // Tells to the driver to resume
489 waveOutRestart( waveout_handle
);
493 // Wakeup playing thread.
496 SetEvent( wakeup_playthread
);
500 } //if status == WAVEOUT_PAUSED
506 if ( status
!= WAVEOUT_READY
)
513 // Prepares WAVEHDR structures.
521 // Sets correct status.
524 status
= WAVEOUT_PLAYING
;
529 // Reads the audio from the start.
532 //audio_buf.set_position_start();
538 // Reads the first N bytes from the audio
539 // buffer, where N = the total size of all
543 audio_buf
.read( main_buffer
, mb_size
);
551 // Wakeup the playing thread.
554 SetEvent( wakeup_playthread
);
560 // Sends all the little buffers to the
561 // audio driver, so it can play the sound
565 for ( i
= 0; i
< buffers
; ++ i
)
569 err
= waveOutWrite( waveout_handle
, &wave_headers
[ i
], sizeof( WAVEHDR
));
571 if ( err
!= MMSYSERR_NOERROR
)
575 MessageBox(0, _T("waveOutWrite Error"), 0, 0);
586 audio_waveout::pause( void )
593 // If the waveout object is not playing audio,
597 if ( status
== WAVEOUT_PLAYING
)
604 status
= WAVEOUT_PAUSED
;
608 // Tells to audio driver to pause audio.
611 err
= waveOutPause( waveout_handle
);
614 if ( err
!= MMSYSERR_NOERROR
)
617 MessageBox(0, _T("waveOutPause Error"), 0, 0);
628 audio_waveout::stop( void )
635 // Checks the current status
638 if (( status
!= WAVEOUT_PLAYING
)
639 && ( status
!= WAVEOUT_FLUSHING
)
640 && ( status
!= WAVEOUT_PAUSED
))
656 status
= WAVEOUT_STOP
;
661 // Flushes pending audio datas
664 err
= waveOutReset( waveout_handle
);
668 if ( err
!= MMSYSERR_NOERROR
)
671 MessageBox(0, _T("err WaveOutReset.\n"),_T("ERROR"), 0);
679 // Sets the start position of the audio
683 audio_buf
.set_position_start();
687 // Cleans little buffers.
696 // Refreshes the status.
699 status
= WAVEOUT_READY
;
704 audio_waveout::close( void )
711 // If the `wave_out' object is playing audio,
712 // or it is in paused state, we have to call
713 // the `stop' member function, to flush
717 if (( status
== WAVEOUT_PLAYING
)
718 || ( status
== WAVEOUT_PAUSED
))
728 // When we have flushed all pending buffers,
729 // the wave out handle can be successfully closed.
732 err
= waveOutClose( waveout_handle
);
735 if ( err
!= MMSYSERR_NOERROR
)
738 MessageBox(0, _T("waveOutClose Error"), 0, 0);
749 audio_waveout::playing_procedure( LPVOID arg
)
754 audio_waveout
* _this
= ( audio_waveout
* ) arg
;
755 unsigned int read_size
;
760 // Check the arg pointer
769 // The thread can go to sleep for now.
770 // It will be wake up only when there is audio data
774 if ( _this
->wakeup_playthread
)
775 WaitForSingleObject(_this
->wakeup_playthread
, INFINITE
);
780 // Entering main polling loop
783 while ( GetMessage( &msg
, 0, 0, 0 ))
786 switch ( msg
.message
)
791 phdr
= ( WAVEHDR
* ) msg
.lParam
;
795 // If the status of the `wave_out' object
796 // is different than playing, then the thread
800 if (( _this
->status
!= WAVEOUT_PLAYING
) &&
801 ( _this
->status
!= WAVEOUT_FLUSHING
) &&
802 ( _this
->wakeup_playthread
))
804 WaitForSingleObject(_this
->wakeup_playthread
, INFINITE
);
810 // The playing thread doesn't have to sleep,
811 // so let's checking first if the little buffer
812 // has been sent to the audio driver (it has the
813 // WHDR_DONE flag). If it is, we can read new
814 // audio datas from the `audio_producer' object,
815 // refill the little buffer, and resend it to the
816 // driver with waveOutWrite( ) API.
819 if ( phdr
->dwFlags
& WHDR_DONE
)
822 if ( _this
->status
== WAVEOUT_PLAYING
)
826 // Here the thread is still playing a sound,
827 // so it can read new audio data from the
828 // `audio_producer' object.
832 _this
->audio_buf
.read(
833 ( BYTE
* ) phdr
->lpData
,
843 // If the `audio_producer' object, has produced some
844 // audio data, so `read_size' will be > 0.
851 // Adjusts the correct effectively read size.
854 phdr
->dwBufferLength
= read_size
;
857 // Before sending the little buffer to the
858 // driver, we have to remove the `WHDR_DONE'
859 // flag, because the little buffer now contain
860 // new audio data that have to be played.
863 phdr
->dwFlags
&= ~WHDR_DONE
;
867 // Plays the sound of the little buffer.
871 _this
->waveout_handle
,
878 // Checking if any error has occured.
881 if ( err
!= MMSYSERR_NOERROR
)
883 MessageBox(0, _T("waveOutWrite Error"), 0, 0);
890 } else { // if ( read_size )
895 // Here `read_size' is 0, so the
896 // `audio_producer' object, doesn't have any
897 // sound data to produce anymore.
898 // So, now we have to see the little buffer
899 // #ID to establishing what to do.
902 if ( phdr
->dwUser
== 0 )
908 // Here `read_size' is 0, and the buffer
909 // user data contain 0, so this is the
910 // first of N little buffers that came
911 // back with `WHDR_DONE' flag; this means
912 // that this is the last little buffer in
913 // which we have to read data to; so we
914 // can _STOP_ reading data from the
915 // `audio_producer' object: doing this is
916 // accomplished just setting the current
917 // status as "WAVEOUT_FLUSHING".
920 _this
->status
= WAVEOUT_FLUSHING
;
923 } else if ( phdr
->dwUser
== ( _this
->buffers
- 1 )) {
928 // Here `read_size' and the buffer user
929 // data, that contain a buffer ID#,
930 // is equal to the number of the total
931 // buffers - 1. This means that this is the
932 // _LAST_ little buffer that has been played
933 // by the audio driver. We can STOP the
934 // `wave_out' object now, or restart the
935 // sound playing, if we have a infinite loop.
942 // Let the thread go to sleep.
945 if ( _this
->audio_buf
.play_finished
)
946 _this
->audio_buf
.play_finished();
949 if ( _this
->wakeup_playthread
)
950 WaitForSingleObject(_this
->wakeup_playthread
,
953 } //if ( phdr->dwUser == ( _this->buffers - 1 ))
955 } //if read_size != 0
957 } //( phdr->dwFlags & WHDR_DONE )
967 // The thread can exit now.
984 } //end switch( msg.message )
986 } //end while( GetMessage( ... ))
992 _AUDIO_NAMESPACE_END_