Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenaudio_wavein.cpp
Go to the documentation of this file.
00001 /* PROJECT: ReactOS sndrec32 00002 * LICENSE: GPL - See COPYING in the top level directory 00003 * FILE: base/applications/sndrec32/audio_wavein.cpp 00004 * PURPOSE: Sound recording 00005 * PROGRAMMERS: Marco Pagliaricci (irc: rendar) 00006 */ 00007 00008 00009 00010 #include "stdafx.h" 00011 #include "audio_wavein.hpp" 00012 00013 00014 00015 _AUDIO_NAMESPACE_START_ 00016 00017 00018 void 00019 audio_wavein::init_( void ) 00020 { 00021 ZeroMemory(( LPVOID ) &wave_format, 00022 sizeof( WAVEFORMATEX )); 00023 00024 wave_format.cbSize = sizeof( WAVEFORMATEX ); 00025 00026 wavein_handle = 0; 00027 recthread_id = 0; 00028 wakeup_recthread = 0; 00029 00030 data_flushed_event = 0; 00031 00032 buf_secs = _AUDIO_DEFAULT_WAVEINBUFSECS; 00033 00034 00035 status = WAVEIN_NOTREADY; 00036 } 00037 00038 00039 void 00040 audio_wavein::alloc_buffers_mem_( unsigned int buffs, float secs ) 00041 { 00042 00043 00044 unsigned int 00045 onebuf_size = 0, tot_size = 0; 00046 00047 00048 // 00049 // Release old memory 00050 // 00051 00052 if ( main_buffer ) 00053 delete[] main_buffer; 00054 00055 00056 if ( wave_headers ) 00057 delete[] wave_headers; 00058 00059 00060 00061 // 00062 // Calcs size of the buffers 00063 // 00064 00065 onebuf_size = ( unsigned int ) 00066 (( float )aud_info.byte_rate() * secs ); 00067 00068 00069 tot_size = onebuf_size * buffs; 00070 00071 00072 00073 00074 // 00075 // Allocs memory for the audio buffers 00076 // 00077 00078 main_buffer = new BYTE [ tot_size ]; 00079 00080 00081 00082 // 00083 // Allocs memory for the `WAVEHDR' structures. 00084 // 00085 00086 wave_headers = ( WAVEHDR * ) 00087 new BYTE [ sizeof( WAVEHDR ) * buffs ]; 00088 00089 00090 00091 // 00092 // Zeros memory. 00093 // 00094 00095 ZeroMemory( main_buffer, tot_size ); 00096 00097 ZeroMemory( wave_headers, 00098 sizeof( WAVEHDR ) * buffs ); 00099 00100 00101 // 00102 // Updates total size of the buffers. 00103 // 00104 00105 mb_size = tot_size; 00106 00107 } 00108 00109 00110 void 00111 audio_wavein::free_buffers_mem_( void ) 00112 { 00113 00114 00115 // 00116 // Frees memory 00117 // 00118 00119 if ( main_buffer ) 00120 delete[] main_buffer; 00121 00122 00123 if ( wave_headers ) 00124 delete[] wave_headers; 00125 00126 00127 main_buffer = 0; 00128 wave_headers = 0; 00129 00130 } 00131 00132 00133 void 00134 audio_wavein::init_headers_( void ) 00135 { 00136 00137 00138 00139 // 00140 // If there is no memory for memory or 00141 // headers, simply return. 00142 // 00143 00144 if (( !wave_headers ) || ( !main_buffer )) 00145 return; 00146 00147 00148 // 00149 // This is the size for one buffer 00150 // 00151 00152 DWORD buf_sz = mb_size / buffers; 00153 00154 00155 00156 // 00157 // This is the base address for one buffer 00158 // 00159 00160 BYTE * buf_addr = main_buffer; 00161 00162 00163 // 00164 // Initializes headers. 00165 // 00166 00167 for ( unsigned int i = 0; i < buffers; ++i ) 00168 { 00169 wave_headers[ i ].dwBufferLength = mb_size / buffers; 00170 wave_headers[ i ].lpData = ( LPSTR ) buf_addr; 00171 00172 buf_addr += buf_sz; 00173 } 00174 00175 } 00176 00177 00178 void 00179 audio_wavein::prep_headers_( void ) 00180 { 00181 MMRESULT err; 00182 bool error = false; 00183 00184 00185 // 00186 // If there is no memory for memory or 00187 // headers, throw error. 00188 // 00189 00190 if (( !wave_headers ) 00191 || ( !main_buffer ) || ( !wavein_handle )) 00192 {} //TODO: throw error! 00193 00194 00195 00196 for ( unsigned int i = 0; i < buffers; ++i ) 00197 { 00198 err = waveInPrepareHeader( wavein_handle, 00199 &wave_headers[ i ], sizeof( WAVEHDR )); 00200 00201 00202 if ( err != MMSYSERR_NOERROR ) 00203 error = true; 00204 00205 } 00206 00207 00208 if ( error ) 00209 MessageBox( 0, TEXT("waveInPrepareHeader Error."), 0, 0 ); 00210 00211 00212 00213 } 00214 00215 void 00216 audio_wavein::unprep_headers_( void ) 00217 { 00218 MMRESULT err; 00219 bool error = false; 00220 00221 00222 00223 // 00224 // If there is no memory for memory or 00225 // headers, throw error. 00226 // 00227 00228 if (( !wave_headers ) 00229 || ( !main_buffer ) || ( !wavein_handle )) 00230 {} //TODO: throw error! 00231 00232 00233 00234 for ( unsigned int i = 0; i < buffers; ++i ) 00235 { 00236 err = waveInUnprepareHeader( wavein_handle, 00237 &wave_headers[ i ], sizeof( WAVEHDR )); 00238 00239 00240 if ( err != MMSYSERR_NOERROR ) 00241 error = true; 00242 00243 } 00244 00245 00246 if ( error ) 00247 MessageBox( 0, TEXT("waveInUnPrepareHeader Error."), 0, 0 ); 00248 00249 } 00250 00251 00252 void 00253 audio_wavein::add_buffers_to_driver_( void ) 00254 { 00255 MMRESULT err; 00256 bool error = false; 00257 00258 00259 00260 // 00261 // If there is no memory for memory or 00262 // headers, throw error. 00263 // 00264 00265 if (( !wave_headers ) 00266 || ( !main_buffer ) || ( !wavein_handle )) 00267 {} //TODO: throw error! 00268 00269 00270 00271 00272 for ( unsigned int i = 0; i < buffers; ++i ) 00273 { 00274 err = waveInAddBuffer( wavein_handle, 00275 &wave_headers[ i ], sizeof( WAVEHDR )); 00276 00277 00278 if ( err != MMSYSERR_NOERROR ) 00279 error = true; 00280 00281 } 00282 00283 00284 if ( error ) 00285 MessageBox( 0, TEXT("waveInAddBuffer Error."), 0, 0 ); 00286 00287 } 00288 00289 00290 00291 void 00292 audio_wavein::close( void ) 00293 { 00294 00295 00296 00297 00298 // 00299 // If wavein object is already in the status 00300 // NOTREADY, nothing to do. 00301 // 00302 00303 if ( status == WAVEIN_NOTREADY ) 00304 return; 00305 00306 00307 00308 // 00309 // If the wavein is recording, 00310 // then stop recording and close it. 00311 // 00312 00313 if ( status == WAVEIN_RECORDING ) 00314 stop_recording(); 00315 00316 00317 // 00318 // Updating status. 00319 // 00320 00321 status = WAVEIN_NOTREADY; 00322 00323 00324 00325 00326 // 00327 // Wakeing up recording thread, so it 00328 // can receive the `MM_WIM_CLOSE' message 00329 // then dies. 00330 // 00331 if ( wakeup_recthread ) 00332 SetEvent( wakeup_recthread ); 00333 00334 00335 00336 // 00337 // Closing wavein stream 00338 // 00339 00340 while (( waveInClose( wavein_handle )) 00341 != MMSYSERR_NOERROR ) Sleep( 1 ); 00342 00343 00344 00345 // 00346 // Release buffers memory. 00347 // 00348 00349 free_buffers_mem_(); 00350 00351 00352 // 00353 // Re-initialize variables to the 00354 // initial state. 00355 // 00356 00357 init_(); 00358 00359 } 00360 00361 00362 void 00363 audio_wavein::open( void ) 00364 { 00365 00366 MMRESULT err; 00367 HANDLE recthread_handle = 0; 00368 00369 00370 // 00371 // Checkin the status of the object 00372 // 00373 00374 if ( status != WAVEIN_NOTREADY ) 00375 {} //TODO: throw error 00376 00377 00378 00379 // 00380 // Creating the EVENT object that will be signaled 00381 // when the recording thread has to wake up. 00382 // 00383 00384 wakeup_recthread = 00385 CreateEvent( 0, FALSE, FALSE, 0 ); 00386 00387 00388 data_flushed_event = 00389 CreateEvent( 0, FALSE, FALSE, 0 ); 00390 00391 00392 00393 if (( !wakeup_recthread ) || ( !data_flushed_event )) 00394 { 00395 00396 00397 status = WAVEIN_ERR; 00398 00399 MessageBox( 0, TEXT("Thread Error."), 0, 0 ); 00400 00401 //TODO: throw error 00402 } 00403 00404 00405 00406 // 00407 // Inialize buffers for recording audio 00408 // data from the wavein audio line. 00409 // 00410 00411 alloc_buffers_mem_( buffers, buf_secs ); 00412 init_headers_(); 00413 00414 00415 00416 00417 00418 00419 // 00420 // Sound format that will be captured by wavein 00421 // 00422 00423 wave_format.wFormatTag = WAVE_FORMAT_PCM; 00424 00425 wave_format.nChannels = aud_info.channels(); 00426 wave_format.nSamplesPerSec = aud_info.sample_rate(); 00427 wave_format.wBitsPerSample = aud_info.bits(); 00428 wave_format.nBlockAlign = aud_info.block_align(); 00429 wave_format.nAvgBytesPerSec = aud_info.byte_rate(); 00430 00431 00432 00433 // 00434 // Creating the recording thread 00435 // 00436 00437 recthread_handle = 00438 CreateThread( NULL, 00439 0, 00440 audio_wavein::recording_procedure, 00441 ( PVOID ) this, 00442 0, 00443 &recthread_id 00444 ); 00445 00446 00447 00448 // 00449 // Checking thread handle 00450 // 00451 00452 if ( !recthread_handle ) 00453 { 00454 00455 // 00456 // Updating status 00457 // 00458 00459 status = WAVEIN_ERR; 00460 00461 MessageBox( 0, TEXT("Thread Error."), 0, 0 ); 00462 //TODO: throw error 00463 00464 } 00465 00466 00467 // 00468 // We don't need the thread handle anymore, 00469 // so we can close it from now. (We'll just 00470 // need the thread ID for the `waveInOpen' API) 00471 // 00472 00473 CloseHandle( recthread_handle ); 00474 00475 00476 00477 // 00478 // Opening audio line wavein 00479 // 00480 00481 err = waveInOpen( &wavein_handle, 00482 0, 00483 &wave_format, 00484 recthread_id, 00485 0, 00486 CALLBACK_THREAD 00487 ); 00488 00489 00490 if ( err != MMSYSERR_NOERROR ) 00491 { 00492 00493 00494 // 00495 // Updating status 00496 // 00497 00498 status = WAVEIN_ERR; 00499 00500 if ( err == WAVERR_BADFORMAT ) 00501 MessageBox( 0, TEXT("waveInOpen Error"), 0, 0 ); 00502 00503 00504 //TODO: throw error 00505 } 00506 00507 00508 // 00509 // Update object status 00510 // 00511 00512 status = WAVEIN_READY; 00513 00514 00515 00516 // 00517 // Now `audio_wavein' object is ready 00518 // for audio recording! 00519 // 00520 } 00521 00522 00523 00524 void 00525 audio_wavein::start_recording( void ) 00526 { 00527 00528 MMRESULT err; 00529 BOOL ev; 00530 00531 00532 00533 if (( status != WAVEIN_READY ) 00534 && ( status != WAVEIN_STOP )) 00535 {} //TODO: throw error 00536 00537 00538 00539 00540 // 00541 // Updating to the recording status 00542 // 00543 00544 status = WAVEIN_RECORDING; 00545 00546 00547 00548 00549 // 00550 // Let's prepare header of type WAVEHDR that 00551 // we will pass to the driver with our 00552 // audio informations, and buffer informations. 00553 // 00554 00555 prep_headers_(); 00556 00557 00558 00559 // 00560 // The waveInAddBuffer function sends an input buffer 00561 // to the given waveform-audio input device. 00562 // When the buffer is filled, the application is notified. 00563 // 00564 00565 add_buffers_to_driver_(); 00566 00567 00568 00569 00570 00571 // 00572 // Signaling event for waking up 00573 // the recorder thread. 00574 // 00575 00576 ev = SetEvent( wakeup_recthread ); 00577 00578 00579 if ( !ev ) 00580 { 00581 00582 00583 MessageBox( 0, TEXT("Event Error."), 0, 0 ); 00584 00585 } 00586 00587 00588 // 00589 // Start recording 00590 // 00591 00592 00593 err = waveInStart( wavein_handle ); 00594 00595 00596 if ( err != MMSYSERR_NOERROR ) 00597 { 00598 00599 // 00600 // Updating status 00601 // 00602 00603 status = WAVEIN_ERR; 00604 00605 MessageBox( 0, TEXT("waveInStart Error."), 0, 0 ); 00606 00607 00608 //TODO: throw error 00609 00610 } 00611 00612 } 00613 00614 00615 00616 void 00617 audio_wavein::stop_recording( void ) 00618 { 00619 00620 00621 MMRESULT err; 00622 00623 if ( status != WAVEIN_RECORDING ) 00624 return; 00625 00626 00627 00628 status = WAVEIN_FLUSHING; 00629 00630 00631 // 00632 // waveInReset will make all pending buffer as done. 00633 // 00634 00635 err = waveInReset( wavein_handle ); 00636 00637 00638 if ( err != MMSYSERR_NOERROR ) 00639 { 00640 00641 //TODO: throw error 00642 00643 MessageBox( 0, TEXT("waveInReset Error."), 0, 0 ); 00644 00645 00646 00647 } 00648 00649 00650 if ( data_flushed_event ) 00651 WaitForSingleObject(data_flushed_event, INFINITE); 00652 00653 00654 00655 00656 00657 00658 00659 // 00660 // Stop recording. 00661 // 00662 00663 err = waveInStop( wavein_handle ); 00664 00665 00666 if ( err != MMSYSERR_NOERROR ) 00667 { 00668 00669 //TODO: throw error 00670 00671 MessageBox( 0, TEXT("waveInStop Error."), 0, 0 ); 00672 00673 00674 00675 } 00676 00677 00678 // 00679 // The waveInUnprepareHeader function cleans up the 00680 // preparation performed by the waveInPrepareHeader function. 00681 // 00682 00683 unprep_headers_(); 00684 00685 00686 00687 00688 00689 00690 00691 00692 00693 00694 00695 status = WAVEIN_STOP; 00696 00697 } 00698 00699 00700 00701 DWORD WINAPI 00702 audio_wavein::recording_procedure( LPVOID arg ) 00703 { 00704 00705 00706 MSG msg; 00707 WAVEHDR * phdr; 00708 audio_wavein * _this = ( audio_wavein * ) arg; 00709 00710 00711 00712 00713 // 00714 // Check the arg pointer 00715 // 00716 00717 if ( _this == 0 ) 00718 return 0; 00719 00720 00721 00722 // 00723 // The thread can go to sleep for now. 00724 // It will be wake up only when there is audio data 00725 // to be recorded. 00726 // 00727 00728 if ( _this->wakeup_recthread ) 00729 WaitForSingleObject(_this->wakeup_recthread, INFINITE); 00730 00731 00732 00733 00734 00735 00736 // 00737 // If status of the `audio_wavein' object 00738 // is not ready or recording the thread can exit. 00739 // 00740 00741 if (( _this->status != WAVEIN_READY ) && 00742 ( _this->status != WAVEIN_RECORDING )) 00743 return 0; 00744 00745 00746 00747 00748 00749 00750 00751 // 00752 // Entering main polling loop 00753 // 00754 00755 while ( GetMessage( &msg, 0, 0, 0 )) 00756 { 00757 00758 switch ( msg.message ) 00759 { 00760 00761 case MM_WIM_DATA: 00762 00763 phdr = ( WAVEHDR * ) msg.lParam; 00764 00765 if (( _this->status == WAVEIN_RECORDING ) 00766 || ( _this->status == WAVEIN_FLUSHING )) 00767 { 00768 00769 00770 if ( phdr->dwFlags & WHDR_DONE ) 00771 { 00772 00773 // 00774 // Flushes recorded audio data to 00775 // the `audio_receiver' object. 00776 // 00777 00778 _this->audio_rcvd.audio_receive( 00779 ( unsigned char * )phdr->lpData, 00780 phdr->dwBytesRecorded 00781 ); 00782 00783 00784 // 00785 // Updating `audio_receiver' total 00786 // bytes received _AFTER_ calling 00787 // `audio_receive' function. 00788 // 00789 00790 _this->audio_rcvd.bytes_received += 00791 phdr->dwBytesRecorded; 00792 } 00793 00794 00795 00796 // 00797 // If status is not flushing data, then 00798 // we can re-add the buffer for reusing it. 00799 // Otherwise, if we are flushing pending data, 00800 // we cannot re-add buffer because we don't need 00801 // it anymore 00802 // 00803 00804 if ( _this->status != WAVEIN_FLUSHING ) 00805 { 00806 00807 // 00808 // Let the audio driver reuse the buffer 00809 // 00810 00811 waveInAddBuffer( _this->wavein_handle, 00812 phdr, sizeof( WAVEHDR )); 00813 00814 00815 } else { 00816 00817 // 00818 // If we are flushing pending data, we have 00819 // to prepare to stop recording. 00820 // Set WAVEHDR flag to 0, and fires the event 00821 // `data_flushed_event', that will wake up 00822 // the main thread that is sleeping into 00823 // wavein_in::stop_recording() member function, 00824 // waiting the last `MM_WIM_DATA' message that 00825 // contain pending data. 00826 // 00827 00828 phdr->dwFlags = 0; 00829 00830 SetEvent( _this->data_flushed_event ); 00831 00832 00833 // 00834 // The recording is gooing to stop, so the 00835 // recording thread can go to sleep! 00836 // 00837 00838 WaitForSingleObject(_this->wakeup_recthread, INFINITE); 00839 00840 } 00841 00842 00843 }//if WAVEIN_RECORDING || WAVEIN_FLUSHING 00844 00845 break; 00846 00847 00848 00849 00850 00851 00852 00853 00854 00855 case MM_WIM_CLOSE: 00856 00857 // 00858 // The thread can exit now. 00859 // 00860 00861 return 0; 00862 00863 break; 00864 00865 00866 00867 } //end switch( msg.message ) 00868 00869 } //end while( GetMessage( ... )) 00870 00871 return 0; 00872 } 00873 00874 00875 00876 00877 00878 00879 _AUDIO_NAMESPACE_END_ Generated on Sat May 26 2012 04:16:26 for ReactOS by
1.7.6.1
|