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 )
467 { return; } //TODO; throw error, or assert
473 // If the status is PAUSED, we have to
474 // resume the audio playing.
476 if ( status
== WAVEOUT_PAUSED
)
483 status
= WAVEOUT_PLAYING
;
487 // Tells to the driver to resume
491 waveOutRestart( waveout_handle
);
495 // Wakeup playing thread.
498 ev
= SetEvent( wakeup_playthread
);
502 } //if status == WAVEOUT_PAUSED
508 if ( status
!= WAVEOUT_READY
)
515 // Prepares WAVEHDR structures.
523 // Sets correct status.
526 status
= WAVEOUT_PLAYING
;
531 // Reads the audio from the start.
534 //audio_buf.set_position_start();
540 // Reads the first N bytes from the audio
541 // buffer, where N = the total size of all
545 audio_buf
.read( main_buffer
, mb_size
);
553 // Wakeup the playing thread.
556 ev
= SetEvent( wakeup_playthread
);
562 // Sends all the little buffers to the
563 // audio driver, so it can play the sound
567 for ( i
= 0; i
< buffers
; ++ i
)
571 err
= waveOutWrite( waveout_handle
, &wave_headers
[ i
], sizeof( WAVEHDR
));
573 if ( err
!= MMSYSERR_NOERROR
)
577 MessageBox(0, _T("waveOutWrite Error"), 0, 0);
588 audio_waveout::pause( void )
595 // If the waveout object is not playing audio,
599 if ( status
== WAVEOUT_PLAYING
)
606 status
= WAVEOUT_PAUSED
;
610 // Tells to audio driver to pause audio.
613 err
= waveOutPause( waveout_handle
);
616 if ( err
!= MMSYSERR_NOERROR
)
619 MessageBox(0, _T("waveOutPause Error"), 0, 0);
630 audio_waveout::stop( void )
637 // Checks the current status
640 if (( status
!= WAVEOUT_PLAYING
)
641 && ( status
!= WAVEOUT_FLUSHING
)
642 && ( status
!= WAVEOUT_PAUSED
))
658 status
= WAVEOUT_STOP
;
663 // Flushes pending audio datas
666 err
= waveOutReset( waveout_handle
);
670 if ( err
!= MMSYSERR_NOERROR
)
673 MessageBox(0, _T("err WaveOutReset.\n"),_T("ERROR"), 0);
681 // Sets the start position of the audio
685 audio_buf
.set_position_start();
689 // Cleans little buffers.
698 // Refreshes the status.
701 status
= WAVEOUT_READY
;
706 audio_waveout::close( void )
713 // If the `wave_out' object is playing audio,
714 // or it is in paused state, we have to call
715 // the `stop' member function, to flush
719 if (( status
== WAVEOUT_PLAYING
)
720 || ( status
== WAVEOUT_PAUSED
))
730 // When we have flushed all pending buffers,
731 // the wave out handle can be successfully closed.
734 err
= waveOutClose( waveout_handle
);
737 if ( err
!= MMSYSERR_NOERROR
)
740 MessageBox(0, _T("waveOutClose Error"), 0, 0);
751 audio_waveout::playing_procedure( LPVOID arg
)
757 audio_waveout
* _this
= ( audio_waveout
* ) arg
;
758 unsigned int read_size
;
763 // Check the arg pointer
772 // The thread can go to sleep for now.
773 // It will be wake up only when there is audio data
777 if ( _this
->wakeup_playthread
)
778 wait
= WaitForSingleObject(
779 _this
->wakeup_playthread
, INFINITE
785 // Entering main polling loop
788 while ( GetMessage( &msg
, 0, 0, 0 ))
791 switch ( msg
.message
)
796 phdr
= ( WAVEHDR
* ) msg
.lParam
;
800 // If the status of the `wave_out' object
801 // is different than playing, then the thread
805 if (( _this
->status
!= WAVEOUT_PLAYING
) &&
806 ( _this
->status
!= WAVEOUT_FLUSHING
) &&
807 ( _this
->wakeup_playthread
))
810 wait
= WaitForSingleObject(
811 _this
->wakeup_playthread
,
819 // The playing thread doesn't have to sleep,
820 // so let's checking first if the little buffer
821 // has been sent to the audio driver (it has the
822 // WHDR_DONE flag). If it is, we can read new
823 // audio datas from the `audio_producer' object,
824 // refill the little buffer, and resend it to the
825 // driver with waveOutWrite( ) API.
828 if ( phdr
->dwFlags
& WHDR_DONE
)
831 if ( _this
->status
== WAVEOUT_PLAYING
)
835 // Here the thread is still playing a sound,
836 // so it can read new audio data from the
837 // `audio_producer' object.
841 _this
->audio_buf
.read(
842 ( BYTE
* ) phdr
->lpData
,
852 // If the `audio_producer' object, has produced some
853 // audio data, so `read_size' will be > 0.
860 // Adjusts the correct effectively read size.
863 phdr
->dwBufferLength
= read_size
;
866 // Before sending the little buffer to the
867 // driver, we have to remove the `WHDR_DONE'
868 // flag, because the little buffer now contain
869 // new audio data that have to be played.
872 phdr
->dwFlags
&= ~WHDR_DONE
;
876 // Plays the sound of the little buffer.
880 _this
->waveout_handle
,
887 // Checking if any error has occured.
890 if ( err
!= MMSYSERR_NOERROR
)
892 MessageBox(0, _T("waveOutWrite Error"), 0, 0);
899 } else { // if ( read_size )
904 // Here `read_size' is 0, so the
905 // `audio_producer' object, doesn't have any
906 // sound data to produce anymore.
907 // So, now we have to see the little buffer
908 // #ID to establishing what to do.
911 if ( phdr
->dwUser
== 0 )
917 // Here `read_size' is 0, and the buffer
918 // user data contain 0, so this is the
919 // first of N little buffers that came
920 // back with `WHDR_DONE' flag; this means
921 // that this is the last little buffer in
922 // which we have to read data to; so we
923 // can _STOP_ reading data from the
924 // `audio_producer' object: doing this is
925 // accomplished just setting the current
926 // status as "WAVEOUT_FLUSHING".
929 _this
->status
= WAVEOUT_FLUSHING
;
932 } else if ( phdr
->dwUser
== ( _this
->buffers
- 1 )) {
937 // Here `read_size' and the buffer user
938 // data, that contain a buffer ID#,
939 // is equal to the number of the total
940 // buffers - 1. This means that this is the
941 // _LAST_ little buffer that has been played
942 // by the audio driver. We can STOP the
943 // `wave_out' object now, or restart the
944 // sound playing, if we have a infinite loop.
951 // Let the thread go to sleep.
954 if ( _this
->audio_buf
.play_finished
)
955 _this
->audio_buf
.play_finished();
958 if ( _this
->wakeup_playthread
)
959 wait
= WaitForSingleObject(
960 _this
->wakeup_playthread
,
964 } //if ( phdr->dwUser == ( _this->buffers - 1 ))
966 } //if read_size != 0
968 } //( phdr->dwFlags & WHDR_DONE )
978 // The thread can exit now.
995 } //end switch( msg.message )
997 } //end while( GetMessage( ... ))
1003 _AUDIO_NAMESPACE_END_