* Sync with recent trunk (r52637).
[reactos.git] / 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 // lenght 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 BOOL ev;
464
465
466 if ( !main_buffer )
467 { return; } //TODO; throw error, or assert
468
469
470
471
472 //
473 // If the status is PAUSED, we have to
474 // resume the audio playing.
475 //
476 if ( status == WAVEOUT_PAUSED )
477 {
478
479 //
480 // Updates status.
481 //
482
483 status = WAVEOUT_PLAYING;
484
485
486 //
487 // Tells to the driver to resume
488 // audio playing.
489 //
490
491 waveOutRestart( waveout_handle );
492
493
494 //
495 // Wakeup playing thread.
496 //
497
498 ev = SetEvent( wakeup_playthread );
499
500 return;
501
502 } //if status == WAVEOUT_PAUSED
503
504
505
506
507
508 if ( status != WAVEOUT_READY )
509 return;
510
511
512
513
514 //
515 // Prepares WAVEHDR structures.
516 //
517
518 prep_headers_();
519
520
521
522 //
523 // Sets correct status.
524 //
525
526 status = WAVEOUT_PLAYING;
527
528
529
530 //
531 // Reads the audio from the start.
532 //
533
534 //audio_buf.set_position_start();
535
536
537
538
539 //
540 // Reads the first N bytes from the audio
541 // buffer, where N = the total size of all
542 // little buffers.
543 //
544
545 audio_buf.read( main_buffer, mb_size );
546
547
548
549
550
551
552 //
553 // Wakeup the playing thread.
554 //
555
556 ev = SetEvent( wakeup_playthread );
557
558
559
560
561 //
562 // Sends all the little buffers to the
563 // audio driver, so it can play the sound
564 // data.
565 //
566
567 for ( i = 0; i < buffers; ++ i )
568 {
569
570
571 err = waveOutWrite( waveout_handle, &wave_headers[ i ], sizeof( WAVEHDR ));
572
573 if ( err != MMSYSERR_NOERROR )
574 {
575
576
577 MessageBox(0, _T("waveOutWrite Error"), 0, 0);
578
579 //TODO: throw error
580 }
581
582 }
583
584 }
585
586
587 void
588 audio_waveout::pause( void )
589 {
590
591 MMRESULT err;
592
593
594 //
595 // If the waveout object is not playing audio,
596 // do nothing.
597 //
598
599 if ( status == WAVEOUT_PLAYING )
600 {
601
602 //
603 // Updating status.
604 //
605
606 status = WAVEOUT_PAUSED;
607
608
609 //
610 // Tells to audio driver to pause audio.
611 //
612
613 err = waveOutPause( waveout_handle );
614
615
616 if ( err != MMSYSERR_NOERROR )
617 {
618
619 MessageBox(0, _T("waveOutPause Error"), 0, 0);
620 //TODO: throw error
621
622 }
623
624 }
625
626 }
627
628
629 void
630 audio_waveout::stop( void )
631 {
632
633 MMRESULT err;
634
635
636 //
637 // Checks the current status
638 //
639
640 if (( status != WAVEOUT_PLAYING )
641 && ( status != WAVEOUT_FLUSHING )
642 && ( status != WAVEOUT_PAUSED ))
643 {
644 //
645 // Do nothing.
646 //
647
648 return;
649
650 }
651
652
653
654 //
655 // Sets a new status
656 //
657
658 status = WAVEOUT_STOP;
659
660
661
662 //
663 // Flushes pending audio datas
664 //
665
666 err = waveOutReset( waveout_handle );
667
668
669
670 if ( err != MMSYSERR_NOERROR )
671 {
672
673 MessageBox(0, _T("err WaveOutReset.\n"),_T("ERROR"), 0);
674 //TODO: throw error
675
676 }
677
678
679
680 //
681 // Sets the start position of the audio
682 // buffer.
683 //
684
685 audio_buf.set_position_start();
686
687
688 //
689 // Cleans little buffers.
690 //
691
692 unprep_headers_();
693 init_headers_();
694
695
696
697 //
698 // Refreshes the status.
699 //
700
701 status = WAVEOUT_READY;
702
703 }
704
705 void
706 audio_waveout::close( void )
707 {
708
709 MMRESULT err;
710
711
712 //
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
716 // pending buffers.
717 //
718
719 if (( status == WAVEOUT_PLAYING )
720 || ( status== WAVEOUT_PAUSED ))
721 {
722
723 stop();
724
725 }
726
727
728
729 //
730 // When we have flushed all pending buffers,
731 // the wave out handle can be successfully closed.
732 //
733
734 err = waveOutClose( waveout_handle );
735
736
737 if ( err != MMSYSERR_NOERROR )
738 {
739
740 MessageBox(0, _T("waveOutClose Error"), 0, 0);
741 //TODO: throw error
742
743 }
744
745 free_buffers_mem_();
746
747 }
748
749
750 DWORD WINAPI
751 audio_waveout::playing_procedure( LPVOID arg )
752 {
753 MSG msg;
754 WAVEHDR * phdr;
755 DWORD wait;
756 MMRESULT err;
757 audio_waveout * _this = ( audio_waveout * ) arg;
758 unsigned int read_size;
759
760
761
762 //
763 // Check the arg pointer
764 //
765
766 if ( _this == 0 )
767 return 0;
768
769
770
771 //
772 // The thread can go to sleep for now.
773 // It will be wake up only when there is audio data
774 // to be recorded.
775 //
776
777 if ( _this->wakeup_playthread )
778 wait = WaitForSingleObject(
779 _this->wakeup_playthread, INFINITE
780 );
781
782
783
784 //
785 // Entering main polling loop
786 //
787
788 while ( GetMessage( &msg, 0, 0, 0 ))
789 {
790
791 switch ( msg.message )
792 {
793
794 case MM_WOM_DONE:
795
796 phdr = ( WAVEHDR * ) msg.lParam;
797
798
799 //
800 // If the status of the `wave_out' object
801 // is different than playing, then the thread
802 // can go to sleep.
803 //
804
805 if (( _this->status != WAVEOUT_PLAYING ) &&
806 ( _this->status != WAVEOUT_FLUSHING ) &&
807 ( _this->wakeup_playthread ))
808 {
809
810 wait = WaitForSingleObject(
811 _this->wakeup_playthread,
812 INFINITE
813 );
814 }
815
816
817
818 //
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.
826 //
827
828 if ( phdr->dwFlags & WHDR_DONE )
829 {
830
831 if ( _this->status == WAVEOUT_PLAYING )
832 {
833
834 //
835 // Here the thread is still playing a sound,
836 // so it can read new audio data from the
837 // `audio_producer' object.
838 //
839
840 read_size =
841 _this->audio_buf.read(
842 ( BYTE * ) phdr->lpData,
843 phdr->dwBufferLength
844 );
845
846 } else
847 read_size = 0;
848
849
850
851 //
852 // If the `audio_producer' object, has produced some
853 // audio data, so `read_size' will be > 0.
854 //
855
856 if ( read_size )
857 {
858
859 //
860 // Adjusts the correct effectively read size.
861 //
862
863 phdr->dwBufferLength = read_size;
864
865 //
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.
870 //
871
872 phdr->dwFlags &= ~WHDR_DONE;
873
874
875 //
876 // Plays the sound of the little buffer.
877 //
878
879 err = waveOutWrite(
880 _this->waveout_handle,
881 phdr,
882 sizeof( WAVEHDR )
883 );
884
885
886 //
887 // Checking if any error has occured.
888 //
889
890 if ( err != MMSYSERR_NOERROR )
891 {
892 MessageBox(0, _T("waveOutWrite Error"), 0, 0);
893 //TODO: throw error
894 }
895
896
897
898
899 } else { // if ( read_size )
900
901
902
903 //
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.
909 //
910
911 if ( phdr->dwUser == 0 )
912 {
913
914
915
916 //
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".
927 //
928
929 _this->status = WAVEOUT_FLUSHING;
930
931
932 } else if ( phdr->dwUser == ( _this->buffers - 1 )) {
933
934
935
936 //
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.
945 //
946
947
948 _this->stop();
949
950 //
951 // Let the thread go to sleep.
952 //
953
954 if ( _this->audio_buf.play_finished )
955 _this->audio_buf.play_finished();
956
957
958 if ( _this->wakeup_playthread )
959 wait = WaitForSingleObject(
960 _this->wakeup_playthread,
961 INFINITE
962 );
963
964 } //if ( phdr->dwUser == ( _this->buffers - 1 ))
965
966 } //if read_size != 0
967
968 } //( phdr->dwFlags & WHDR_DONE )
969
970
971 break; // end case
972
973
974
975 case MM_WOM_CLOSE:
976
977 //
978 // The thread can exit now.
979 //
980
981 return 0;
982
983 break;
984
985
986 case MM_WOM_OPEN:
987
988 //
989 // Do nothing.
990 //
991
992 break;
993
994
995 } //end switch( msg.message )
996
997 } //end while( GetMessage( ... ))
998
999 return 0;
1000 }
1001
1002
1003 _AUDIO_NAMESPACE_END_