c49627d35bd560bfe5430cd1ecb6e0a7498c76e3
[reactos.git] / reactos / base / applications / sndrec32 / audio_waveout.cpp
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)
6 */
7
8
9
10 #include "stdafx.h"
11 #include "audio_waveout.hpp"
12
13
14 _AUDIO_NAMESPACE_START_
15
16
17
18 void
19 audio_waveout::init_( void )
20 {
21
22 ZeroMemory(( LPVOID ) &wave_format,
23 sizeof( WAVEFORMATEX ));
24
25 wave_format.cbSize = sizeof( WAVEFORMATEX );
26
27 waveout_handle = 0;
28
29 playthread_id = 0;
30 wakeup_playthread = 0;
31
32 buf_secs = _AUDIO_DEFAULT_WAVEOUTBUFSECS;
33
34
35 status = WAVEOUT_NOTREADY;
36
37 }
38
39
40
41
42 void
43 audio_waveout::alloc_buffers_mem_( unsigned int buffs, float secs )
44 {
45
46
47 unsigned int
48 onebuf_size = 0, tot_size = 0;
49
50
51 //
52 // Release old memory
53 //
54
55 if ( main_buffer )
56 delete[] main_buffer;
57
58
59 if ( wave_headers )
60 delete[] wave_headers;
61
62
63
64 //
65 // Calcs size of the buffers
66 //
67
68 onebuf_size = ( unsigned int )
69 (( float )aud_info.byte_rate() * secs );
70
71
72 tot_size = onebuf_size * buffs;
73
74
75
76
77 //
78 // Allocs memory for the audio buffers
79 //
80
81 main_buffer = new BYTE [ tot_size ];
82
83
84
85 //
86 // Allocs memory for the `WAVEHDR' structures.
87 //
88
89 wave_headers = ( WAVEHDR * )
90 new BYTE [ sizeof( WAVEHDR ) * buffs ];
91
92
93
94 //
95 // Zeros memory.
96 //
97
98 ZeroMemory( main_buffer, tot_size );
99
100 ZeroMemory( wave_headers,
101 sizeof( WAVEHDR ) * buffs );
102
103
104 //
105 // Updates total size of the buffers.
106 //
107
108 mb_size = tot_size;
109 }
110
111
112 void
113 audio_waveout::init_headers_( void )
114 {
115
116
117
118 //
119 // If there is no memory for memory or
120 // headers, simply return.
121 //
122
123 if (( !wave_headers ) || ( !main_buffer ))
124 return;
125
126
127 //
128 // This is the size for one buffer
129 //
130
131 DWORD buf_sz = mb_size / buffers;
132
133
134
135 //
136 // This is the base address for one buffer
137 //
138
139 BYTE * buf_addr = main_buffer;
140
141
142
143 ZeroMemory( wave_headers, sizeof( WAVEHDR ) * buffers );
144
145
146 //
147 // Initializes headers.
148 //
149
150 for ( unsigned int i = 0; i < buffers; ++i )
151 {
152
153 //
154 // Sets the correct base address and
155 // length for the little buffer.
156 //
157
158 wave_headers[ i ].dwBufferLength = mb_size / buffers;
159 wave_headers[ i ].lpData = ( LPSTR ) buf_addr;
160
161 //
162 // Unsets the WHDR_DONE flag.
163 //
164
165 wave_headers[ i ].dwFlags &= ~WHDR_DONE;
166
167
168
169 //
170 // Sets the WAVEHDR user data with an
171 // unique little buffer ID#
172 //
173
174 wave_headers[ i ].dwUser = ( unsigned int ) i;
175
176
177
178 //
179 // Increments little buffer base address.
180 //
181
182 buf_addr += buf_sz;
183 }
184
185 }
186
187
188 void
189 audio_waveout::prep_headers_( void )
190 {
191 MMRESULT err;
192 bool error = false;
193
194
195 //
196 // If there is no memory for memory or
197 // headers, throw error.
198 //
199
200 if (( !wave_headers )
201 || ( !main_buffer ) || ( !waveout_handle ))
202 {} //TODO: throw error!
203
204
205
206 for ( unsigned int i = 0; i < buffers; ++i )
207 {
208 err = waveOutPrepareHeader( waveout_handle,
209 &wave_headers[ i ], sizeof( WAVEHDR ));
210
211
212 if ( err != MMSYSERR_NOERROR )
213 error = true;
214
215 }
216
217
218 if ( error )
219 {} //TODO: throw error indicating which
220 //header i-th is errorneous
221
222
223
224 }
225
226 void
227 audio_waveout::unprep_headers_( void )
228 {
229 MMRESULT err;
230 bool error = false;
231
232
233
234 //
235 // If there is no memory for memory or
236 // headers, throw error.
237 //
238
239 if (( !wave_headers )
240 || ( !main_buffer ) || ( !waveout_handle ))
241 {} //TODO: throw error!
242
243
244
245 for ( unsigned int i = 0; i < buffers; ++i )
246 {
247 err = waveOutUnprepareHeader( waveout_handle,
248 &wave_headers[ i ], sizeof( WAVEHDR ));
249
250
251 if ( err != MMSYSERR_NOERROR )
252 error = true;
253
254 }
255
256
257 if ( error )
258 {} //TODO: throw error indicating which
259 //header i-th is errorneous
260
261 }
262
263
264
265
266
267
268
269
270
271 void
272 audio_waveout::free_buffers_mem_( void )
273 {
274
275
276
277 //
278 // Frees memory
279 //
280
281 if ( main_buffer )
282 delete[] main_buffer;
283
284
285 if ( wave_headers )
286 delete[] wave_headers;
287
288
289 main_buffer = 0;
290 wave_headers = 0;
291
292
293
294
295 }
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310 void
311 audio_waveout::open( void )
312 {
313
314 MMRESULT err;
315 HANDLE playthread_handle = 0;
316
317
318 //
319 // Checkin the status of the object
320 //
321
322 if ( status != WAVEOUT_NOTREADY )
323 {} //TODO: throw error
324
325
326 //
327 // Creating the EVENT object that will be signaled
328 // when the playing thread has to wake up.
329 //
330
331 wakeup_playthread =
332 CreateEvent( 0, FALSE, FALSE, 0 );
333
334 if ( !wakeup_playthread )
335 {
336
337
338 status = WAVEOUT_ERR;
339
340 //TODO: throw error
341 }
342
343
344
345 //
346 // Inialize buffers for recording audio
347 // data from the wavein audio line.
348 //
349
350 alloc_buffers_mem_( buffers, buf_secs );
351 init_headers_();
352
353
354
355
356
357
358 //
359 // Sound format that will be captured by wavein
360 //
361
362 wave_format.wFormatTag = WAVE_FORMAT_PCM;
363
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();
369
370
371
372 //
373 // Creating the recording thread
374 //
375
376 playthread_handle =
377 CreateThread( NULL,
378 0,
379 audio_waveout::playing_procedure,
380 ( PVOID ) this,
381 0,
382 &playthread_id
383 );
384
385
386
387 //
388 // Checking thread handle
389 //
390
391 if ( !playthread_handle )
392 {
393
394 //
395 // Updating status
396 //
397
398 status = WAVEOUT_ERR;
399 //TODO: throw error
400
401 }
402
403
404 //
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)
408 //
409
410 CloseHandle( playthread_handle );
411
412
413
414 //
415 // Reset the `audio_source' to the start
416 // position.
417 //
418
419 audio_buf.set_position_start();
420
421
422
423
424 //
425 // Opens the WAVE_OUT device.
426 //
427
428 err = waveOutOpen(
429 &waveout_handle,
430 WAVE_MAPPER,
431 &wave_format,
432 playthread_id,
433 0,
434 CALLBACK_THREAD | WAVE_ALLOWSYNC
435 );
436
437
438
439 if ( err != MMSYSERR_NOERROR )
440 {
441 MessageBox(0, _T("waveOutOpen Error"), 0, 0);
442 //TODO: throw error
443
444 }
445
446
447
448
449 status = WAVEOUT_READY;
450
451
452 }
453
454
455
456 void
457 audio_waveout::play( void )
458 {
459
460
461 MMRESULT err;
462 unsigned int i;
463
464 if ( !main_buffer )
465 { return; } //TODO; throw error, or assert
466
467
468
469
470 //
471 // If the status is PAUSED, we have to
472 // resume the audio playing.
473 //
474 if ( status == WAVEOUT_PAUSED )
475 {
476
477 //
478 // Updates status.
479 //
480
481 status = WAVEOUT_PLAYING;
482
483
484 //
485 // Tells to the driver to resume
486 // audio playing.
487 //
488
489 waveOutRestart( waveout_handle );
490
491
492 //
493 // Wakeup playing thread.
494 //
495
496 SetEvent( wakeup_playthread );
497
498 return;
499
500 } //if status == WAVEOUT_PAUSED
501
502
503
504
505
506 if ( status != WAVEOUT_READY )
507 return;
508
509
510
511
512 //
513 // Prepares WAVEHDR structures.
514 //
515
516 prep_headers_();
517
518
519
520 //
521 // Sets correct status.
522 //
523
524 status = WAVEOUT_PLAYING;
525
526
527
528 //
529 // Reads the audio from the start.
530 //
531
532 //audio_buf.set_position_start();
533
534
535
536
537 //
538 // Reads the first N bytes from the audio
539 // buffer, where N = the total size of all
540 // little buffers.
541 //
542
543 audio_buf.read( main_buffer, mb_size );
544
545
546
547
548
549
550 //
551 // Wakeup the playing thread.
552 //
553
554 SetEvent( wakeup_playthread );
555
556
557
558
559 //
560 // Sends all the little buffers to the
561 // audio driver, so it can play the sound
562 // data.
563 //
564
565 for ( i = 0; i < buffers; ++ i )
566 {
567
568
569 err = waveOutWrite( waveout_handle, &wave_headers[ i ], sizeof( WAVEHDR ));
570
571 if ( err != MMSYSERR_NOERROR )
572 {
573
574
575 MessageBox(0, _T("waveOutWrite Error"), 0, 0);
576
577 //TODO: throw error
578 }
579
580 }
581
582 }
583
584
585 void
586 audio_waveout::pause( void )
587 {
588
589 MMRESULT err;
590
591
592 //
593 // If the waveout object is not playing audio,
594 // do nothing.
595 //
596
597 if ( status == WAVEOUT_PLAYING )
598 {
599
600 //
601 // Updating status.
602 //
603
604 status = WAVEOUT_PAUSED;
605
606
607 //
608 // Tells to audio driver to pause audio.
609 //
610
611 err = waveOutPause( waveout_handle );
612
613
614 if ( err != MMSYSERR_NOERROR )
615 {
616
617 MessageBox(0, _T("waveOutPause Error"), 0, 0);
618 //TODO: throw error
619
620 }
621
622 }
623
624 }
625
626
627 void
628 audio_waveout::stop( void )
629 {
630
631 MMRESULT err;
632
633
634 //
635 // Checks the current status
636 //
637
638 if (( status != WAVEOUT_PLAYING )
639 && ( status != WAVEOUT_FLUSHING )
640 && ( status != WAVEOUT_PAUSED ))
641 {
642 //
643 // Do nothing.
644 //
645
646 return;
647
648 }
649
650
651
652 //
653 // Sets a new status
654 //
655
656 status = WAVEOUT_STOP;
657
658
659
660 //
661 // Flushes pending audio datas
662 //
663
664 err = waveOutReset( waveout_handle );
665
666
667
668 if ( err != MMSYSERR_NOERROR )
669 {
670
671 MessageBox(0, _T("err WaveOutReset.\n"),_T("ERROR"), 0);
672 //TODO: throw error
673
674 }
675
676
677
678 //
679 // Sets the start position of the audio
680 // buffer.
681 //
682
683 audio_buf.set_position_start();
684
685
686 //
687 // Cleans little buffers.
688 //
689
690 unprep_headers_();
691 init_headers_();
692
693
694
695 //
696 // Refreshes the status.
697 //
698
699 status = WAVEOUT_READY;
700
701 }
702
703 void
704 audio_waveout::close( void )
705 {
706
707 MMRESULT err;
708
709
710 //
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
714 // pending buffers.
715 //
716
717 if (( status == WAVEOUT_PLAYING )
718 || ( status== WAVEOUT_PAUSED ))
719 {
720
721 stop();
722
723 }
724
725
726
727 //
728 // When we have flushed all pending buffers,
729 // the wave out handle can be successfully closed.
730 //
731
732 err = waveOutClose( waveout_handle );
733
734
735 if ( err != MMSYSERR_NOERROR )
736 {
737
738 MessageBox(0, _T("waveOutClose Error"), 0, 0);
739 //TODO: throw error
740
741 }
742
743 free_buffers_mem_();
744
745 }
746
747
748 DWORD WINAPI
749 audio_waveout::playing_procedure( LPVOID arg )
750 {
751 MSG msg;
752 WAVEHDR * phdr;
753 MMRESULT err;
754 audio_waveout * _this = ( audio_waveout * ) arg;
755 unsigned int read_size;
756
757
758
759 //
760 // Check the arg pointer
761 //
762
763 if ( _this == 0 )
764 return 0;
765
766
767
768 //
769 // The thread can go to sleep for now.
770 // It will be wake up only when there is audio data
771 // to be recorded.
772 //
773
774 if ( _this->wakeup_playthread )
775 WaitForSingleObject(_this->wakeup_playthread, INFINITE);
776
777
778
779 //
780 // Entering main polling loop
781 //
782
783 while ( GetMessage( &msg, 0, 0, 0 ))
784 {
785
786 switch ( msg.message )
787 {
788
789 case MM_WOM_DONE:
790
791 phdr = ( WAVEHDR * ) msg.lParam;
792
793
794 //
795 // If the status of the `wave_out' object
796 // is different than playing, then the thread
797 // can go to sleep.
798 //
799
800 if (( _this->status != WAVEOUT_PLAYING ) &&
801 ( _this->status != WAVEOUT_FLUSHING ) &&
802 ( _this->wakeup_playthread ))
803 {
804 WaitForSingleObject(_this->wakeup_playthread, INFINITE);
805 }
806
807
808
809 //
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.
817 //
818
819 if ( phdr->dwFlags & WHDR_DONE )
820 {
821
822 if ( _this->status == WAVEOUT_PLAYING )
823 {
824
825 //
826 // Here the thread is still playing a sound,
827 // so it can read new audio data from the
828 // `audio_producer' object.
829 //
830
831 read_size =
832 _this->audio_buf.read(
833 ( BYTE * ) phdr->lpData,
834 phdr->dwBufferLength
835 );
836
837 } else
838 read_size = 0;
839
840
841
842 //
843 // If the `audio_producer' object, has produced some
844 // audio data, so `read_size' will be > 0.
845 //
846
847 if ( read_size )
848 {
849
850 //
851 // Adjusts the correct effectively read size.
852 //
853
854 phdr->dwBufferLength = read_size;
855
856 //
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.
861 //
862
863 phdr->dwFlags &= ~WHDR_DONE;
864
865
866 //
867 // Plays the sound of the little buffer.
868 //
869
870 err = waveOutWrite(
871 _this->waveout_handle,
872 phdr,
873 sizeof( WAVEHDR )
874 );
875
876
877 //
878 // Checking if any error has occured.
879 //
880
881 if ( err != MMSYSERR_NOERROR )
882 {
883 MessageBox(0, _T("waveOutWrite Error"), 0, 0);
884 //TODO: throw error
885 }
886
887
888
889
890 } else { // if ( read_size )
891
892
893
894 //
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.
900 //
901
902 if ( phdr->dwUser == 0 )
903 {
904
905
906
907 //
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".
918 //
919
920 _this->status = WAVEOUT_FLUSHING;
921
922
923 } else if ( phdr->dwUser == ( _this->buffers - 1 )) {
924
925
926
927 //
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.
936 //
937
938
939 _this->stop();
940
941 //
942 // Let the thread go to sleep.
943 //
944
945 if ( _this->audio_buf.play_finished )
946 _this->audio_buf.play_finished();
947
948
949 if ( _this->wakeup_playthread )
950 WaitForSingleObject(_this->wakeup_playthread,
951 INFINITE);
952
953 } //if ( phdr->dwUser == ( _this->buffers - 1 ))
954
955 } //if read_size != 0
956
957 } //( phdr->dwFlags & WHDR_DONE )
958
959
960 break; // end case
961
962
963
964 case MM_WOM_CLOSE:
965
966 //
967 // The thread can exit now.
968 //
969
970 return 0;
971
972 break;
973
974
975 case MM_WOM_OPEN:
976
977 //
978 // Do nothing.
979 //
980
981 break;
982
983
984 } //end switch( msg.message )
985
986 } //end while( GetMessage( ... ))
987
988 return 0;
989 }
990
991
992 _AUDIO_NAMESPACE_END_