Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenaudio_waveout.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_waveout.cpp 00004 * PURPOSE: Sound recording 00005 * PROGRAMMERS: Marco Pagliaricci (irc: rendar) 00006 */ 00007 00008 00009 00010 #include "stdafx.h" 00011 #include "audio_waveout.hpp" 00012 00013 00014 _AUDIO_NAMESPACE_START_ 00015 00016 00017 00018 void 00019 audio_waveout::init_( void ) 00020 { 00021 00022 ZeroMemory(( LPVOID ) &wave_format, 00023 sizeof( WAVEFORMATEX )); 00024 00025 wave_format.cbSize = sizeof( WAVEFORMATEX ); 00026 00027 waveout_handle = 0; 00028 00029 playthread_id = 0; 00030 wakeup_playthread = 0; 00031 00032 buf_secs = _AUDIO_DEFAULT_WAVEOUTBUFSECS; 00033 00034 00035 status = WAVEOUT_NOTREADY; 00036 00037 } 00038 00039 00040 00041 00042 void 00043 audio_waveout::alloc_buffers_mem_( unsigned int buffs, float secs ) 00044 { 00045 00046 00047 unsigned int 00048 onebuf_size = 0, tot_size = 0; 00049 00050 00051 // 00052 // Release old memory 00053 // 00054 00055 if ( main_buffer ) 00056 delete[] main_buffer; 00057 00058 00059 if ( wave_headers ) 00060 delete[] wave_headers; 00061 00062 00063 00064 // 00065 // Calcs size of the buffers 00066 // 00067 00068 onebuf_size = ( unsigned int ) 00069 (( float )aud_info.byte_rate() * secs ); 00070 00071 00072 tot_size = onebuf_size * buffs; 00073 00074 00075 00076 00077 // 00078 // Allocs memory for the audio buffers 00079 // 00080 00081 main_buffer = new BYTE [ tot_size ]; 00082 00083 00084 00085 // 00086 // Allocs memory for the `WAVEHDR' structures. 00087 // 00088 00089 wave_headers = ( WAVEHDR * ) 00090 new BYTE [ sizeof( WAVEHDR ) * buffs ]; 00091 00092 00093 00094 // 00095 // Zeros memory. 00096 // 00097 00098 ZeroMemory( main_buffer, tot_size ); 00099 00100 ZeroMemory( wave_headers, 00101 sizeof( WAVEHDR ) * buffs ); 00102 00103 00104 // 00105 // Updates total size of the buffers. 00106 // 00107 00108 mb_size = tot_size; 00109 } 00110 00111 00112 void 00113 audio_waveout::init_headers_( void ) 00114 { 00115 00116 00117 00118 // 00119 // If there is no memory for memory or 00120 // headers, simply return. 00121 // 00122 00123 if (( !wave_headers ) || ( !main_buffer )) 00124 return; 00125 00126 00127 // 00128 // This is the size for one buffer 00129 // 00130 00131 DWORD buf_sz = mb_size / buffers; 00132 00133 00134 00135 // 00136 // This is the base address for one buffer 00137 // 00138 00139 BYTE * buf_addr = main_buffer; 00140 00141 00142 00143 ZeroMemory( wave_headers, sizeof( WAVEHDR ) * buffers ); 00144 00145 00146 // 00147 // Initializes headers. 00148 // 00149 00150 for ( unsigned int i = 0; i < buffers; ++i ) 00151 { 00152 00153 // 00154 // Sets the correct base address and 00155 // lenght for the little buffer. 00156 // 00157 00158 wave_headers[ i ].dwBufferLength = mb_size / buffers; 00159 wave_headers[ i ].lpData = ( LPSTR ) buf_addr; 00160 00161 // 00162 // Unsets the WHDR_DONE flag. 00163 // 00164 00165 wave_headers[ i ].dwFlags &= ~WHDR_DONE; 00166 00167 00168 00169 // 00170 // Sets the WAVEHDR user data with an 00171 // unique little buffer ID# 00172 // 00173 00174 wave_headers[ i ].dwUser = ( unsigned int ) i; 00175 00176 00177 00178 // 00179 // Increments little buffer base address. 00180 // 00181 00182 buf_addr += buf_sz; 00183 } 00184 00185 } 00186 00187 00188 void 00189 audio_waveout::prep_headers_( void ) 00190 { 00191 MMRESULT err; 00192 bool error = false; 00193 00194 00195 // 00196 // If there is no memory for memory or 00197 // headers, throw error. 00198 // 00199 00200 if (( !wave_headers ) 00201 || ( !main_buffer ) || ( !waveout_handle )) 00202 {} //TODO: throw error! 00203 00204 00205 00206 for ( unsigned int i = 0; i < buffers; ++i ) 00207 { 00208 err = waveOutPrepareHeader( waveout_handle, 00209 &wave_headers[ i ], sizeof( WAVEHDR )); 00210 00211 00212 if ( err != MMSYSERR_NOERROR ) 00213 error = true; 00214 00215 } 00216 00217 00218 if ( error ) 00219 {} //TODO: throw error indicating which 00220 //header i-th is errorneous 00221 00222 00223 00224 } 00225 00226 void 00227 audio_waveout::unprep_headers_( void ) 00228 { 00229 MMRESULT err; 00230 bool error = false; 00231 00232 00233 00234 // 00235 // If there is no memory for memory or 00236 // headers, throw error. 00237 // 00238 00239 if (( !wave_headers ) 00240 || ( !main_buffer ) || ( !waveout_handle )) 00241 {} //TODO: throw error! 00242 00243 00244 00245 for ( unsigned int i = 0; i < buffers; ++i ) 00246 { 00247 err = waveOutUnprepareHeader( waveout_handle, 00248 &wave_headers[ i ], sizeof( WAVEHDR )); 00249 00250 00251 if ( err != MMSYSERR_NOERROR ) 00252 error = true; 00253 00254 } 00255 00256 00257 if ( error ) 00258 {} //TODO: throw error indicating which 00259 //header i-th is errorneous 00260 00261 } 00262 00263 00264 00265 00266 00267 00268 00269 00270 00271 void 00272 audio_waveout::free_buffers_mem_( void ) 00273 { 00274 00275 00276 00277 // 00278 // Frees memory 00279 // 00280 00281 if ( main_buffer ) 00282 delete[] main_buffer; 00283 00284 00285 if ( wave_headers ) 00286 delete[] wave_headers; 00287 00288 00289 main_buffer = 0; 00290 wave_headers = 0; 00291 00292 00293 00294 00295 } 00296 00297 00298 00299 00300 00301 00302 00303 00304 00305 00306 00307 00308 00309 00310 void 00311 audio_waveout::open( void ) 00312 { 00313 00314 MMRESULT err; 00315 HANDLE playthread_handle = 0; 00316 00317 00318 // 00319 // Checkin the status of the object 00320 // 00321 00322 if ( status != WAVEOUT_NOTREADY ) 00323 {} //TODO: throw error 00324 00325 00326 // 00327 // Creating the EVENT object that will be signaled 00328 // when the playing thread has to wake up. 00329 // 00330 00331 wakeup_playthread = 00332 CreateEvent( 0, FALSE, FALSE, 0 ); 00333 00334 if ( !wakeup_playthread ) 00335 { 00336 00337 00338 status = WAVEOUT_ERR; 00339 00340 //TODO: throw error 00341 } 00342 00343 00344 00345 // 00346 // Inialize buffers for recording audio 00347 // data from the wavein audio line. 00348 // 00349 00350 alloc_buffers_mem_( buffers, buf_secs ); 00351 init_headers_(); 00352 00353 00354 00355 00356 00357 00358 // 00359 // Sound format that will be captured by wavein 00360 // 00361 00362 wave_format.wFormatTag = WAVE_FORMAT_PCM; 00363 00364 wave_format.nChannels = aud_info.channels(); 00365 wave_format.nSamplesPerSec = aud_info.sample_rate(); 00366 wave_format.wBitsPerSample = aud_info.bits(); 00367 wave_format.nBlockAlign = aud_info.block_align(); 00368 wave_format.nAvgBytesPerSec = aud_info.byte_rate(); 00369 00370 00371 00372 // 00373 // Creating the recording thread 00374 // 00375 00376 playthread_handle = 00377 CreateThread( NULL, 00378 0, 00379 audio_waveout::playing_procedure, 00380 ( PVOID ) this, 00381 0, 00382 &playthread_id 00383 ); 00384 00385 00386 00387 // 00388 // Checking thread handle 00389 // 00390 00391 if ( !playthread_handle ) 00392 { 00393 00394 // 00395 // Updating status 00396 // 00397 00398 status = WAVEOUT_ERR; 00399 //TODO: throw error 00400 00401 } 00402 00403 00404 // 00405 // We don't need the thread handle anymore, 00406 // so we can close it from now. (We'll just 00407 // need the thread ID for the `waveInOpen' API) 00408 // 00409 00410 CloseHandle( playthread_handle ); 00411 00412 00413 00414 // 00415 // Reset the `audio_source' to the start 00416 // position. 00417 // 00418 00419 audio_buf.set_position_start(); 00420 00421 00422 00423 00424 // 00425 // Opens the WAVE_OUT device. 00426 // 00427 00428 err = waveOutOpen( 00429 &waveout_handle, 00430 WAVE_MAPPER, 00431 &wave_format, 00432 playthread_id, 00433 0, 00434 CALLBACK_THREAD | WAVE_ALLOWSYNC 00435 ); 00436 00437 00438 00439 if ( err != MMSYSERR_NOERROR ) 00440 { 00441 MessageBox(0, _T("waveOutOpen Error"), 0, 0); 00442 //TODO: throw error 00443 00444 } 00445 00446 00447 00448 00449 status = WAVEOUT_READY; 00450 00451 00452 } 00453 00454 00455 00456 void 00457 audio_waveout::play( void ) 00458 { 00459 00460 00461 MMRESULT err; 00462 unsigned int i; 00463 00464 if ( !main_buffer ) 00465 { return; } //TODO; throw error, or assert 00466 00467 00468 00469 00470 // 00471 // If the status is PAUSED, we have to 00472 // resume the audio playing. 00473 // 00474 if ( status == WAVEOUT_PAUSED ) 00475 { 00476 00477 // 00478 // Updates status. 00479 // 00480 00481 status = WAVEOUT_PLAYING; 00482 00483 00484 // 00485 // Tells to the driver to resume 00486 // audio playing. 00487 // 00488 00489 waveOutRestart( waveout_handle ); 00490 00491 00492 // 00493 // Wakeup playing thread. 00494 // 00495 00496 SetEvent( wakeup_playthread ); 00497 00498 return; 00499 00500 } //if status == WAVEOUT_PAUSED 00501 00502 00503 00504 00505 00506 if ( status != WAVEOUT_READY ) 00507 return; 00508 00509 00510 00511 00512 // 00513 // Prepares WAVEHDR structures. 00514 // 00515 00516 prep_headers_(); 00517 00518 00519 00520 // 00521 // Sets correct status. 00522 // 00523 00524 status = WAVEOUT_PLAYING; 00525 00526 00527 00528 // 00529 // Reads the audio from the start. 00530 // 00531 00532 //audio_buf.set_position_start(); 00533 00534 00535 00536 00537 // 00538 // Reads the first N bytes from the audio 00539 // buffer, where N = the total size of all 00540 // little buffers. 00541 // 00542 00543 audio_buf.read( main_buffer, mb_size ); 00544 00545 00546 00547 00548 00549 00550 // 00551 // Wakeup the playing thread. 00552 // 00553 00554 SetEvent( wakeup_playthread ); 00555 00556 00557 00558 00559 // 00560 // Sends all the little buffers to the 00561 // audio driver, so it can play the sound 00562 // data. 00563 // 00564 00565 for ( i = 0; i < buffers; ++ i ) 00566 { 00567 00568 00569 err = waveOutWrite( waveout_handle, &wave_headers[ i ], sizeof( WAVEHDR )); 00570 00571 if ( err != MMSYSERR_NOERROR ) 00572 { 00573 00574 00575 MessageBox(0, _T("waveOutWrite Error"), 0, 0); 00576 00577 //TODO: throw error 00578 } 00579 00580 } 00581 00582 } 00583 00584 00585 void 00586 audio_waveout::pause( void ) 00587 { 00588 00589 MMRESULT err; 00590 00591 00592 // 00593 // If the waveout object is not playing audio, 00594 // do nothing. 00595 // 00596 00597 if ( status == WAVEOUT_PLAYING ) 00598 { 00599 00600 // 00601 // Updating status. 00602 // 00603 00604 status = WAVEOUT_PAUSED; 00605 00606 00607 // 00608 // Tells to audio driver to pause audio. 00609 // 00610 00611 err = waveOutPause( waveout_handle ); 00612 00613 00614 if ( err != MMSYSERR_NOERROR ) 00615 { 00616 00617 MessageBox(0, _T("waveOutPause Error"), 0, 0); 00618 //TODO: throw error 00619 00620 } 00621 00622 } 00623 00624 } 00625 00626 00627 void 00628 audio_waveout::stop( void ) 00629 { 00630 00631 MMRESULT err; 00632 00633 00634 // 00635 // Checks the current status 00636 // 00637 00638 if (( status != WAVEOUT_PLAYING ) 00639 && ( status != WAVEOUT_FLUSHING ) 00640 && ( status != WAVEOUT_PAUSED )) 00641 { 00642 // 00643 // Do nothing. 00644 // 00645 00646 return; 00647 00648 } 00649 00650 00651 00652 // 00653 // Sets a new status 00654 // 00655 00656 status = WAVEOUT_STOP; 00657 00658 00659 00660 // 00661 // Flushes pending audio datas 00662 // 00663 00664 err = waveOutReset( waveout_handle ); 00665 00666 00667 00668 if ( err != MMSYSERR_NOERROR ) 00669 { 00670 00671 MessageBox(0, _T("err WaveOutReset.\n"),_T("ERROR"), 0); 00672 //TODO: throw error 00673 00674 } 00675 00676 00677 00678 // 00679 // Sets the start position of the audio 00680 // buffer. 00681 // 00682 00683 audio_buf.set_position_start(); 00684 00685 00686 // 00687 // Cleans little buffers. 00688 // 00689 00690 unprep_headers_(); 00691 init_headers_(); 00692 00693 00694 00695 // 00696 // Refreshes the status. 00697 // 00698 00699 status = WAVEOUT_READY; 00700 00701 } 00702 00703 void 00704 audio_waveout::close( void ) 00705 { 00706 00707 MMRESULT err; 00708 00709 00710 // 00711 // If the `wave_out' object is playing audio, 00712 // or it is in paused state, we have to call 00713 // the `stop' member function, to flush 00714 // pending buffers. 00715 // 00716 00717 if (( status == WAVEOUT_PLAYING ) 00718 || ( status== WAVEOUT_PAUSED )) 00719 { 00720 00721 stop(); 00722 00723 } 00724 00725 00726 00727 // 00728 // When we have flushed all pending buffers, 00729 // the wave out handle can be successfully closed. 00730 // 00731 00732 err = waveOutClose( waveout_handle ); 00733 00734 00735 if ( err != MMSYSERR_NOERROR ) 00736 { 00737 00738 MessageBox(0, _T("waveOutClose Error"), 0, 0); 00739 //TODO: throw error 00740 00741 } 00742 00743 free_buffers_mem_(); 00744 00745 } 00746 00747 00748 DWORD WINAPI 00749 audio_waveout::playing_procedure( LPVOID arg ) 00750 { 00751 MSG msg; 00752 WAVEHDR * phdr; 00753 MMRESULT err; 00754 audio_waveout * _this = ( audio_waveout * ) arg; 00755 unsigned int read_size; 00756 00757 00758 00759 // 00760 // Check the arg pointer 00761 // 00762 00763 if ( _this == 0 ) 00764 return 0; 00765 00766 00767 00768 // 00769 // The thread can go to sleep for now. 00770 // It will be wake up only when there is audio data 00771 // to be recorded. 00772 // 00773 00774 if ( _this->wakeup_playthread ) 00775 WaitForSingleObject(_this->wakeup_playthread, INFINITE); 00776 00777 00778 00779 // 00780 // Entering main polling loop 00781 // 00782 00783 while ( GetMessage( &msg, 0, 0, 0 )) 00784 { 00785 00786 switch ( msg.message ) 00787 { 00788 00789 case MM_WOM_DONE: 00790 00791 phdr = ( WAVEHDR * ) msg.lParam; 00792 00793 00794 // 00795 // If the status of the `wave_out' object 00796 // is different than playing, then the thread 00797 // can go to sleep. 00798 // 00799 00800 if (( _this->status != WAVEOUT_PLAYING ) && 00801 ( _this->status != WAVEOUT_FLUSHING ) && 00802 ( _this->wakeup_playthread )) 00803 { 00804 WaitForSingleObject(_this->wakeup_playthread, INFINITE); 00805 } 00806 00807 00808 00809 // 00810 // The playing thread doesn't have to sleep, 00811 // so let's checking first if the little buffer 00812 // has been sent to the audio driver (it has the 00813 // WHDR_DONE flag). If it is, we can read new 00814 // audio datas from the `audio_producer' object, 00815 // refill the little buffer, and resend it to the 00816 // driver with waveOutWrite( ) API. 00817 // 00818 00819 if ( phdr->dwFlags & WHDR_DONE ) 00820 { 00821 00822 if ( _this->status == WAVEOUT_PLAYING ) 00823 { 00824 00825 // 00826 // Here the thread is still playing a sound, 00827 // so it can read new audio data from the 00828 // `audio_producer' object. 00829 // 00830 00831 read_size = 00832 _this->audio_buf.read( 00833 ( BYTE * ) phdr->lpData, 00834 phdr->dwBufferLength 00835 ); 00836 00837 } else 00838 read_size = 0; 00839 00840 00841 00842 // 00843 // If the `audio_producer' object, has produced some 00844 // audio data, so `read_size' will be > 0. 00845 // 00846 00847 if ( read_size ) 00848 { 00849 00850 // 00851 // Adjusts the correct effectively read size. 00852 // 00853 00854 phdr->dwBufferLength = read_size; 00855 00856 // 00857 // Before sending the little buffer to the 00858 // driver, we have to remove the `WHDR_DONE' 00859 // flag, because the little buffer now contain 00860 // new audio data that have to be played. 00861 // 00862 00863 phdr->dwFlags &= ~WHDR_DONE; 00864 00865 00866 // 00867 // Plays the sound of the little buffer. 00868 // 00869 00870 err = waveOutWrite( 00871 _this->waveout_handle, 00872 phdr, 00873 sizeof( WAVEHDR ) 00874 ); 00875 00876 00877 // 00878 // Checking if any error has occured. 00879 // 00880 00881 if ( err != MMSYSERR_NOERROR ) 00882 { 00883 MessageBox(0, _T("waveOutWrite Error"), 0, 0); 00884 //TODO: throw error 00885 } 00886 00887 00888 00889 00890 } else { // if ( read_size ) 00891 00892 00893 00894 // 00895 // Here `read_size' is 0, so the 00896 // `audio_producer' object, doesn't have any 00897 // sound data to produce anymore. 00898 // So, now we have to see the little buffer 00899 // #ID to establishing what to do. 00900 // 00901 00902 if ( phdr->dwUser == 0 ) 00903 { 00904 00905 00906 00907 // 00908 // Here `read_size' is 0, and the buffer 00909 // user data contain 0, so this is the 00910 // first of N little buffers that came 00911 // back with `WHDR_DONE' flag; this means 00912 // that this is the last little buffer in 00913 // which we have to read data to; so we 00914 // can _STOP_ reading data from the 00915 // `audio_producer' object: doing this is 00916 // accomplished just setting the current 00917 // status as "WAVEOUT_FLUSHING". 00918 // 00919 00920 _this->status = WAVEOUT_FLUSHING; 00921 00922 00923 } else if ( phdr->dwUser == ( _this->buffers - 1 )) { 00924 00925 00926 00927 // 00928 // Here `read_size' and the buffer user 00929 // data, that contain a buffer ID#, 00930 // is equal to the number of the total 00931 // buffers - 1. This means that this is the 00932 // _LAST_ little buffer that has been played 00933 // by the audio driver. We can STOP the 00934 // `wave_out' object now, or restart the 00935 // sound playing, if we have a infinite loop. 00936 // 00937 00938 00939 _this->stop(); 00940 00941 // 00942 // Let the thread go to sleep. 00943 // 00944 00945 if ( _this->audio_buf.play_finished ) 00946 _this->audio_buf.play_finished(); 00947 00948 00949 if ( _this->wakeup_playthread ) 00950 WaitForSingleObject(_this->wakeup_playthread, 00951 INFINITE); 00952 00953 } //if ( phdr->dwUser == ( _this->buffers - 1 )) 00954 00955 } //if read_size != 0 00956 00957 } //( phdr->dwFlags & WHDR_DONE ) 00958 00959 00960 break; // end case 00961 00962 00963 00964 case MM_WOM_CLOSE: 00965 00966 // 00967 // The thread can exit now. 00968 // 00969 00970 return 0; 00971 00972 break; 00973 00974 00975 case MM_WOM_OPEN: 00976 00977 // 00978 // Do nothing. 00979 // 00980 00981 break; 00982 00983 00984 } //end switch( msg.message ) 00985 00986 } //end while( GetMessage( ... )) 00987 00988 return 0; 00989 } 00990 00991 00992 _AUDIO_NAMESPACE_END_ Generated on Fri May 25 2012 04:15:49 for ReactOS by
1.7.6.1
|