2 Copyright (C) 2009 Red Hat, Inc.
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, see <http://www.gnu.org/licenses/>.
26 #define RING_SIZE_MS 500
28 static void CALLBACK in_proc(HWAVEIN handle, UINT msg, DWORD user_data, DWORD param1,
31 WaveRecorder* recorder = (WaveRecorder*)user_data;
35 WaveRecorder::WaveRecorder(Platform::RecordClient& client, uint32_t sampels_per_sec,
36 uint32_t bits_per_sample, uint32_t channels)
46 info.wFormatTag = WAVE_FORMAT_PCM;
47 info.nChannels = channels;
48 info.nSamplesPerSec = sampels_per_sec;
49 info.nBlockAlign = frame_align = channels * bits_per_sample / 8;
50 info.nAvgBytesPerSec = sampels_per_sec * info.nBlockAlign;
51 info.wBitsPerSample = bits_per_sample;
54 if (waveInOpen(&_wave_in, WAVE_MAPPER, &info, (DWORD_PTR)in_proc, (DWORD_PTR)this,
55 CALLBACK_FUNCTION) != MMSYSERR_NOERROR) {
56 throw Exception("cannot open playback device");
60 const int frame_size = WavePlaybackAbstract::FRAME_SIZE;
61 uint32_t frame_bytes = frame_size * channels * bits_per_sample / 8;
63 _frame = new uint8_t[frame_bytes];
65 _frame_end = _frame + frame_bytes;
66 init_ring(sampels_per_sec, frame_bytes, frame_align);
67 _client.add_event_source(*this);
71 waveInClose(_wave_in);
76 WaveRecorder::~WaveRecorder()
78 waveInReset(_wave_in);
80 _client.remove_event_source(*this);
81 waveInClose(_wave_in);
86 void WaveRecorder::init_ring(uint32_t sampels_per_sec, uint32_t frame_bytes, uint32_t frame_align)
88 const int frame_size = WavePlaybackAbstract::FRAME_SIZE;
90 _ring_size = (sampels_per_sec * RING_SIZE_MS / 1000) / frame_size;
91 _ring_item_size = sizeof(WAVEHDR) + frame_bytes + frame_align;
93 int ring_bytes = _ring_size * _ring_item_size;
94 _ring = new uint8_t[ring_bytes];
97 uint8_t* end = ptr + ring_bytes;
98 for (; ptr != end; ptr += _ring_item_size) {
99 WAVEHDR* buf = (WAVEHDR*)ptr;
100 memset(ptr, 0, _ring_item_size);
101 buf->dwBufferLength = frame_bytes;
102 ULONG_PTR ptr = (ULONG_PTR)(buf + 1);
103 ptr = (ptr + frame_align - 1) / frame_align * frame_align;
104 buf->lpData = (LPSTR)(buf + 1);
108 void WaveRecorder::start()
111 waveInReset(_wave_in);
113 waveInStart(_wave_in);
116 inline WAVEHDR* WaveRecorder::wave_hader(uint32_t position)
118 ASSERT(position < _ring_size);
119 return (WAVEHDR*)(_ring + position * _ring_item_size);
122 inline void WaveRecorder::move_head()
124 _head = (_head + 1) % _ring_size;
128 void WaveRecorder::push_frames()
130 while (_in_use != _ring_size) {
131 WAVEHDR* buff = wave_hader((_head + _in_use) % _ring_size);
134 MMRESULT err = waveInPrepareHeader(_wave_in, buff, sizeof(WAVEHDR));
135 if (err != MMSYSERR_NOERROR) {
136 THROW("waveInPrepareHeader filed %d", err);
138 err = waveInAddBuffer(_wave_in, buff, sizeof(WAVEHDR));
139 if (err != MMSYSERR_NOERROR) {
140 THROW("waveInAddBuffer filed %d", err);
145 void WaveRecorder::on_event()
148 WAVEHDR* front_buf = wave_hader(_head);
149 if (!(front_buf->dwFlags & WHDR_DONE)) {
152 waveInUnprepareHeader(_wave_in, front_buf, sizeof(WAVEHDR));
153 front_buf->dwFlags &= ~WHDR_DONE;
154 int n = front_buf->dwBytesRecorded;
155 front_buf->dwBytesRecorded = 0;
156 uint8_t* ptr = (uint8_t*)front_buf->lpData;
158 int now = MIN(n, _frame_end - _frame_pos);
159 memcpy(_frame_pos, ptr, now);
160 if ((_frame_pos += n) == _frame_end) {
161 _client.push_frame(_frame);
172 void WaveRecorder::reclaim()
175 WAVEHDR* front_buf = wave_hader(_head);
176 if (!(front_buf->dwFlags & WHDR_DONE)) {
179 waveInUnprepareHeader(_wave_in, front_buf, sizeof(WAVEHDR));
180 front_buf->dwFlags &= ~WHDR_DONE;
181 front_buf->dwBytesRecorded = 0;
186 void WaveRecorder::stop()
188 waveInReset(_wave_in);
192 bool WaveRecorder::abort()