ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

audio_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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.