Something went wrong. Try again.
Reactos
Something went wrong. Try again.
12 kB · 419 lines
C++
at listview
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420/* PROJECT: ReactOS sndrec32 * LICENSE: GPL - See COPYING in the top level directory * FILE: base/applications/sndrec32/audio_wavein.cpp * PURPOSE: Sound recording * PROGRAMMERS: Marco Pagliaricci (irc: rendar) */
#include "stdafx.h"#include "audio_wavein.hpp"
_AUDIO_NAMESPACE_START_
voidaudio_wavein::init_(void){ ZeroMemory((LPVOID)&wave_format, sizeof(WAVEFORMATEX)); wave_format.cbSize = sizeof(WAVEFORMATEX); wavein_handle = 0; recthread_id = 0; wakeup_recthread = 0; data_flushed_event = 0; buf_secs = _AUDIO_DEFAULT_WAVEINBUFSECS; status = WAVEIN_NOTREADY;}
voidaudio_wavein::alloc_buffers_mem_(unsigned int buffs, float secs){ unsigned int onebuf_size = 0, tot_size = 0;
/* Release old memory */ if (main_buffer) delete[] main_buffer;
if (wave_headers) delete[] wave_headers;
/* Calcs size of the buffers */ onebuf_size = (unsigned int)((float)aud_info.byte_rate() * secs); tot_size = onebuf_size * buffs;
/* Allocs memory for the audio buffers */ main_buffer = new BYTE[tot_size]; /* Allocs memory for the `WAVEHDR' structures */ wave_headers = (WAVEHDR *)new BYTE[sizeof(WAVEHDR) * buffs]; /* Zeros memory */ ZeroMemory(main_buffer, tot_size); ZeroMemory(wave_headers, sizeof(WAVEHDR) * buffs); /* Updates total size of the buffers */ mb_size = tot_size;}
voidaudio_wavein::free_buffers_mem_(void){ /* Frees memory */ if (main_buffer) delete[] main_buffer;
if (wave_headers) delete[] wave_headers;
main_buffer = 0; wave_headers = 0;}
voidaudio_wavein::init_headers_(void){ /* If there is no memory for memory or headers, simply return */ if ((!wave_headers) || (!main_buffer)) return;
/* This is the size for one buffer */ DWORD buf_sz = mb_size / buffers; /* This is the base address for one buffer */ BYTE *buf_addr = main_buffer; /* Initializes headers */ for (unsigned int i = 0; i < buffers; ++i) { wave_headers[i].dwBufferLength = mb_size / buffers; wave_headers[i].lpData = (LPSTR)buf_addr; buf_addr += buf_sz; }}
voidaudio_wavein::prep_headers_(void){ MMRESULT err; bool error = false;
/* If there is no memory for memory or headers, throw error */ if ((!wave_headers) || (!main_buffer) || (!wavein_handle)) { /* TODO: throw error! */ }
for (unsigned int i = 0; i < buffers; ++i) { err = waveInPrepareHeader(wavein_handle, &wave_headers[i], sizeof(WAVEHDR)); if (err != MMSYSERR_NOERROR) error = true; }
if (error) MessageBox(0, TEXT("waveInPrepareHeader Error."), 0, 0);}
voidaudio_wavein::unprep_headers_(void){ MMRESULT err; bool error = false;
/* If there is no memory for memory or headers, throw error */ if ((!wave_headers) || (!main_buffer) || (!wavein_handle)) { /* TODO: throw error! */ }
for (unsigned int i = 0; i < buffers; ++i) { err = waveInUnprepareHeader(wavein_handle, &wave_headers[i], sizeof(WAVEHDR)); if (err != MMSYSERR_NOERROR) error = true; }
if (error) MessageBox(0, TEXT("waveInUnPrepareHeader Error."), 0, 0);}
voidaudio_wavein::add_buffers_to_driver_(void){ MMRESULT err; bool error = false;
/* If there is no memory for memory or headers, throw error */ if ((!wave_headers) || (!main_buffer) || (!wavein_handle)) { /* TODO: throw error! */ }
for (unsigned int i = 0; i < buffers; ++i) { err = waveInAddBuffer(wavein_handle, &wave_headers[i], sizeof(WAVEHDR)); if (err != MMSYSERR_NOERROR) error = true; }
if (error) MessageBox(0, TEXT("waveInAddBuffer Error."), 0, 0);}
voidaudio_wavein::close(void){ /* If wavein object is already in the status NOTREADY, nothing to do */ if (status == WAVEIN_NOTREADY) return;
/* If the wavein is recording, then stop recording and close it */ if (status == WAVEIN_RECORDING) stop_recording();
/* Updating status */ status = WAVEIN_NOTREADY;
/* Waking up recording thread, so it can receive the `MM_WIM_CLOSE' message then dies */ if (wakeup_recthread) SetEvent(wakeup_recthread);
/* Closing wavein stream */ while ((waveInClose(wavein_handle)) != MMSYSERR_NOERROR) Sleep(1);
/* Release buffers memory */ free_buffers_mem_();
/* Re-initialize variables to the initial state */ init_();}
voidaudio_wavein::open(void){ MMRESULT err; HANDLE recthread_handle = 0;
/* Checkin the status of the object */ if (status != WAVEIN_NOTREADY) { /* TODO: throw error */ }
/* Creating the EVENT object that will be signaled when the recording thread has to wake up */ wakeup_recthread = CreateEvent(0, FALSE, FALSE, 0);
data_flushed_event = CreateEvent(0, FALSE, FALSE, 0);
if ((!wakeup_recthread) || (!data_flushed_event)) { status = WAVEIN_ERR; MessageBox(0, TEXT("Thread Error."), 0, 0); /* TODO: throw error */ }
/* Inialize buffers for recording audio data from the wavein audio line */ alloc_buffers_mem_(buffers, buf_secs); init_headers_();
/* Sound format that will be captured by wavein */ wave_format.wFormatTag = WAVE_FORMAT_PCM; wave_format.nChannels = aud_info.channels(); wave_format.nSamplesPerSec = aud_info.sample_rate(); wave_format.wBitsPerSample = aud_info.bits(); wave_format.nBlockAlign = aud_info.block_align(); wave_format.nAvgBytesPerSec = aud_info.byte_rate();
/* Creating the recording thread */ recthread_handle = CreateThread(NULL, 0, audio_wavein::recording_procedure, (PVOID)this, 0, &recthread_id); /* Checking thread handle */ if (!recthread_handle) { /* Updating status */ status = WAVEIN_ERR; MessageBox(0, TEXT("Thread Error."), 0, 0); /* TODO: throw error */ }
/* We don't need the thread handle anymore, so we can close it from now. (We'll just need the thread ID for the `waveInOpen' API) */ CloseHandle(recthread_handle);
/* Opening audio line wavein */ err = waveInOpen(&wavein_handle, 0, &wave_format, recthread_id, 0, CALLBACK_THREAD);
if (err != MMSYSERR_NOERROR) { /* Updating status */ status = WAVEIN_ERR;
if (err == WAVERR_BADFORMAT) MessageBox(0, TEXT("waveInOpen Error"), 0, 0);
/* TODO: throw error */ }
/* Update object status */ status = WAVEIN_READY;
/* Now `audio_wavein' object is ready for audio recording! */}
voidaudio_wavein::start_recording(void){ MMRESULT err; BOOL ev;
if ((status != WAVEIN_READY) && (status != WAVEIN_STOP)) { /* TODO: throw error */ }
/* Updating to the recording status */ status = WAVEIN_RECORDING;
/* Let's prepare header of type WAVEHDR that we will pass to the driver with our audio informations, and buffer informations */ prep_headers_();
/* The waveInAddBuffer function sends an input buffer to the given waveform-audio input device. When the buffer is filled, the application is notified. */ add_buffers_to_driver_();
/* Signaling event for waking up the recorder thread */ ev = SetEvent(wakeup_recthread); if (!ev) MessageBox(0, TEXT("Event Error."), 0, 0);
/* Start recording */ err = waveInStart(wavein_handle); if (err != MMSYSERR_NOERROR) { /* Updating status */ status = WAVEIN_ERR; MessageBox(0, TEXT("waveInStart Error."), 0, 0); /* TODO: throw error */ }}
voidaudio_wavein::stop_recording(void){ MMRESULT err;
if (status != WAVEIN_RECORDING) return;
status = WAVEIN_FLUSHING;
/* waveInReset will make all pending buffer as done */ err = waveInReset(wavein_handle); if ( err != MMSYSERR_NOERROR ) { /* TODO: throw error */ MessageBox(0, TEXT("waveInReset Error."), 0, 0); }
if (data_flushed_event) WaitForSingleObject(data_flushed_event, INFINITE);
/* Stop recording */ err = waveInStop(wavein_handle); if (err != MMSYSERR_NOERROR) { /* TODO: throw error */ MessageBox(0, TEXT("waveInStop Error."), 0, 0); }
/* The waveInUnprepareHeader function cleans up the preparation performed by the waveInPrepareHeader function */ unprep_headers_();
status = WAVEIN_STOP;}
DWORD WINAPIaudio_wavein::recording_procedure(LPVOID arg){ MSG msg; WAVEHDR *phdr; audio_wavein *_this = (audio_wavein *)arg;
/* Check the arg pointer */ if (_this == 0) return 0;
/* The thread can go to sleep for now. It will be wake up only when there is audio data to be recorded */ if (_this->wakeup_recthread) WaitForSingleObject(_this->wakeup_recthread, INFINITE);
/* If status of the `audio_wavein' object is not ready or recording the thread can exit */ if ((_this->status != WAVEIN_READY) && (_this->status != WAVEIN_RECORDING)) return 0;
/* Entering main polling loop */ while (GetMessage(&msg, 0, 0, 0)) { switch (msg.message) { case MM_WIM_DATA: phdr = (WAVEHDR *)msg.lParam;
if ((_this->status == WAVEIN_RECORDING) || (_this->status == WAVEIN_FLUSHING)) { if (phdr->dwFlags & WHDR_DONE) { /* Flushes recorded audio data to the `audio_receiver' object */ _this->audio_rcvd.audio_receive((unsigned char *)phdr->lpData, phdr->dwBytesRecorded);
/* Updating `audio_receiver' total bytes received _AFTER_ calling `audio_receive' function */ _this->audio_rcvd.bytes_received += phdr->dwBytesRecorded; }
/* If status is not flushing data, then we can re-add the buffer for reusing it. Otherwise, if we are flushing pending data, we cannot re-add buffer because we don't need it anymore */ if (_this->status != WAVEIN_FLUSHING) { /* Let the audio driver reuse the buffer */ waveInAddBuffer(_this->wavein_handle, phdr, sizeof(WAVEHDR)); } else { /* If we are flushing pending data, we have to prepare to stop recording. Set WAVEHDR flag to 0, and fires the event `data_flushed_event', that will wake up the main thread that is sleeping into wavein_in::stop_recording() member function, waiting the last `MM_WIM_DATA' message that contain pending data */
phdr->dwFlags = 0; SetEvent(_this->data_flushed_event);
/* The recording is going to stop, so the recording thread can go to sleep! */ WaitForSingleObject(_this->wakeup_recthread, INFINITE); } } /* if WAVEIN_RECORDING || WAVEIN_FLUSHING */ break;
case MM_WIM_CLOSE: /* The thread can exit now */ return 0; break; } /* end switch(msg.message) */ } /* end while(GetMessage(...)) */
return 0;}
_AUDIO_NAMESPACE_END_