Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(67)

Side by Side Diff: webrtc/modules/audio_device/audio_device_buffer.cc

Issue 2269553004: [Reland] Cleanup of the AudioDeviceBuffer class (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « webrtc/modules/audio_device/audio_device_buffer.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source 5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 #include <algorithm> 11 #include <algorithm>
12 12
13 #include "webrtc/modules/audio_device/audio_device_buffer.h" 13 #include "webrtc/modules/audio_device/audio_device_buffer.h"
14 14
15 #include "webrtc/base/arraysize.h" 15 #include "webrtc/base/arraysize.h"
16 #include "webrtc/base/bind.h" 16 #include "webrtc/base/bind.h"
17 #include "webrtc/base/checks.h" 17 #include "webrtc/base/checks.h"
18 #include "webrtc/base/logging.h" 18 #include "webrtc/base/logging.h"
19 #include "webrtc/base/format_macros.h" 19 #include "webrtc/base/format_macros.h"
20 #include "webrtc/base/timeutils.h" 20 #include "webrtc/base/timeutils.h"
21 #include "webrtc/modules/audio_device/audio_device_config.h" 21 #include "webrtc/modules/audio_device/audio_device_config.h"
22 22
23 namespace webrtc { 23 namespace webrtc {
24 24
25 static const int kHighDelayThresholdMs = 300;
26 static const int kLogHighDelayIntervalFrames = 500; // 5 seconds.
27
28 static const char kTimerQueueName[] = "AudioDeviceBufferTimer"; 25 static const char kTimerQueueName[] = "AudioDeviceBufferTimer";
29 26
30 // Time between two sucessive calls to LogStats(). 27 // Time between two sucessive calls to LogStats().
31 static const size_t kTimerIntervalInSeconds = 10; 28 static const size_t kTimerIntervalInSeconds = 10;
32 static const size_t kTimerIntervalInMilliseconds = 29 static const size_t kTimerIntervalInMilliseconds =
33 kTimerIntervalInSeconds * rtc::kNumMillisecsPerSec; 30 kTimerIntervalInSeconds * rtc::kNumMillisecsPerSec;
34 31
35 AudioDeviceBuffer::AudioDeviceBuffer() 32 AudioDeviceBuffer::AudioDeviceBuffer()
36 : _ptrCbAudioTransport(nullptr), 33 : audio_transport_cb_(nullptr),
37 task_queue_(kTimerQueueName), 34 task_queue_(kTimerQueueName),
38 timer_has_started_(false), 35 timer_has_started_(false),
39 _recSampleRate(0), 36 rec_sample_rate_(0),
40 _playSampleRate(0), 37 play_sample_rate_(0),
41 _recChannels(0), 38 rec_channels_(0),
42 _playChannels(0), 39 play_channels_(0),
43 _recChannel(AudioDeviceModule::kChannelBoth), 40 rec_channel_(AudioDeviceModule::kChannelBoth),
44 _recBytesPerSample(0), 41 rec_bytes_per_sample_(0),
45 _playBytesPerSample(0), 42 play_bytes_per_sample_(0),
46 _recSamples(0), 43 rec_samples_per_10ms_(0),
47 _recSize(0), 44 rec_bytes_per_10ms_(0),
48 _playSamples(0), 45 play_samples_per_10ms_(0),
49 _playSize(0), 46 play_bytes_per_10ms_(0),
50 _recFile(*FileWrapper::Create()), 47 current_mic_level_(0),
51 _playFile(*FileWrapper::Create()), 48 new_mic_level_(0),
52 _currentMicLevel(0), 49 typing_status_(false),
53 _newMicLevel(0), 50 play_delay_ms_(0),
54 _typingStatus(false), 51 rec_delay_ms_(0),
55 _playDelayMS(0), 52 clock_drift_(0),
56 _recDelayMS(0),
57 _clockDrift(0),
58 // Set to the interval in order to log on the first occurrence.
59 high_delay_counter_(kLogHighDelayIntervalFrames),
60 num_stat_reports_(0), 53 num_stat_reports_(0),
61 rec_callbacks_(0), 54 rec_callbacks_(0),
62 last_rec_callbacks_(0), 55 last_rec_callbacks_(0),
63 play_callbacks_(0), 56 play_callbacks_(0),
64 last_play_callbacks_(0), 57 last_play_callbacks_(0),
65 rec_samples_(0), 58 rec_samples_(0),
66 last_rec_samples_(0), 59 last_rec_samples_(0),
67 play_samples_(0), 60 play_samples_(0),
68 last_play_samples_(0), 61 last_play_samples_(0),
69 last_log_stat_time_(0) { 62 last_log_stat_time_(0) {
70 LOG(INFO) << "AudioDeviceBuffer::ctor"; 63 LOG(INFO) << "AudioDeviceBuffer::ctor";
71 memset(_recBuffer, 0, kMaxBufferSizeBytes);
72 memset(_playBuffer, 0, kMaxBufferSizeBytes);
73 } 64 }
74 65
75 AudioDeviceBuffer::~AudioDeviceBuffer() { 66 AudioDeviceBuffer::~AudioDeviceBuffer() {
76 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 67 RTC_DCHECK(thread_checker_.CalledOnValidThread());
77 LOG(INFO) << "AudioDeviceBuffer::~dtor"; 68 LOG(INFO) << "AudioDeviceBuffer::~dtor";
78 69
79 size_t total_diff_time = 0; 70 size_t total_diff_time = 0;
80 int num_measurements = 0; 71 int num_measurements = 0;
81 LOG(INFO) << "[playout diff time => #measurements]"; 72 LOG(INFO) << "[playout diff time => #measurements]";
82 for (size_t diff = 0; diff < arraysize(playout_diff_times_); ++diff) { 73 for (size_t diff = 0; diff < arraysize(playout_diff_times_); ++diff) {
83 uint32_t num_elements = playout_diff_times_[diff]; 74 uint32_t num_elements = playout_diff_times_[diff];
84 if (num_elements > 0) { 75 if (num_elements > 0) {
85 total_diff_time += num_elements * diff; 76 total_diff_time += num_elements * diff;
86 num_measurements += num_elements; 77 num_measurements += num_elements;
87 LOG(INFO) << "[" << diff << " => " << num_elements << "]"; 78 LOG(INFO) << "[" << diff << " => " << num_elements << "]";
88 } 79 }
89 } 80 }
90 if (num_measurements > 0) { 81 if (num_measurements > 0) {
91 LOG(INFO) << "total_diff_time: " << total_diff_time; 82 LOG(INFO) << "total_diff_time: " << total_diff_time;
92 LOG(INFO) << "num_measurements: " << num_measurements; 83 LOG(INFO) << "num_measurements: " << num_measurements;
93 LOG(INFO) << "average: " 84 LOG(INFO) << "average: "
94 << static_cast<float>(total_diff_time) / num_measurements; 85 << static_cast<float>(total_diff_time) / num_measurements;
95 } 86 }
96
97 _recFile.Flush();
98 _recFile.CloseFile();
99 delete &_recFile;
100
101 _playFile.Flush();
102 _playFile.CloseFile();
103 delete &_playFile;
104 } 87 }
105 88
106 int32_t AudioDeviceBuffer::RegisterAudioCallback( 89 int32_t AudioDeviceBuffer::RegisterAudioCallback(
107 AudioTransport* audioCallback) { 90 AudioTransport* audio_callback) {
108 LOG(INFO) << __FUNCTION__; 91 LOG(INFO) << __FUNCTION__;
109 rtc::CritScope lock(&_critSectCb); 92 rtc::CritScope lock(&_critSectCb);
110 _ptrCbAudioTransport = audioCallback; 93 audio_transport_cb_ = audio_callback;
111 return 0; 94 return 0;
112 } 95 }
113 96
114 int32_t AudioDeviceBuffer::InitPlayout() { 97 int32_t AudioDeviceBuffer::InitPlayout() {
98 LOG(INFO) << __FUNCTION__;
115 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 99 RTC_DCHECK(thread_checker_.CalledOnValidThread());
116 LOG(INFO) << __FUNCTION__;
117 last_playout_time_ = rtc::TimeMillis(); 100 last_playout_time_ = rtc::TimeMillis();
118 if (!timer_has_started_) { 101 if (!timer_has_started_) {
119 StartTimer(); 102 StartTimer();
120 timer_has_started_ = true; 103 timer_has_started_ = true;
121 } 104 }
122 return 0; 105 return 0;
123 } 106 }
124 107
125 int32_t AudioDeviceBuffer::InitRecording() { 108 int32_t AudioDeviceBuffer::InitRecording() {
109 LOG(INFO) << __FUNCTION__;
126 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 110 RTC_DCHECK(thread_checker_.CalledOnValidThread());
127 LOG(INFO) << __FUNCTION__;
128 if (!timer_has_started_) { 111 if (!timer_has_started_) {
129 StartTimer(); 112 StartTimer();
130 timer_has_started_ = true; 113 timer_has_started_ = true;
131 } 114 }
132 return 0; 115 return 0;
133 } 116 }
134 117
135 int32_t AudioDeviceBuffer::SetRecordingSampleRate(uint32_t fsHz) { 118 int32_t AudioDeviceBuffer::SetRecordingSampleRate(uint32_t fsHz) {
136 LOG(INFO) << "SetRecordingSampleRate(" << fsHz << ")"; 119 LOG(INFO) << "SetRecordingSampleRate(" << fsHz << ")";
137 rtc::CritScope lock(&_critSect); 120 rtc::CritScope lock(&_critSect);
138 _recSampleRate = fsHz; 121 rec_sample_rate_ = fsHz;
139 return 0; 122 return 0;
140 } 123 }
141 124
142 int32_t AudioDeviceBuffer::SetPlayoutSampleRate(uint32_t fsHz) { 125 int32_t AudioDeviceBuffer::SetPlayoutSampleRate(uint32_t fsHz) {
143 LOG(INFO) << "SetPlayoutSampleRate(" << fsHz << ")"; 126 LOG(INFO) << "SetPlayoutSampleRate(" << fsHz << ")";
144 rtc::CritScope lock(&_critSect); 127 rtc::CritScope lock(&_critSect);
145 _playSampleRate = fsHz; 128 play_sample_rate_ = fsHz;
146 return 0; 129 return 0;
147 } 130 }
148 131
149 int32_t AudioDeviceBuffer::RecordingSampleRate() const { 132 int32_t AudioDeviceBuffer::RecordingSampleRate() const {
150 return _recSampleRate; 133 return rec_sample_rate_;
151 } 134 }
152 135
153 int32_t AudioDeviceBuffer::PlayoutSampleRate() const { 136 int32_t AudioDeviceBuffer::PlayoutSampleRate() const {
154 return _playSampleRate; 137 return play_sample_rate_;
155 } 138 }
156 139
157 int32_t AudioDeviceBuffer::SetRecordingChannels(size_t channels) { 140 int32_t AudioDeviceBuffer::SetRecordingChannels(size_t channels) {
141 LOG(INFO) << "SetRecordingChannels(" << channels << ")";
158 rtc::CritScope lock(&_critSect); 142 rtc::CritScope lock(&_critSect);
159 _recChannels = channels; 143 rec_channels_ = channels;
160 _recBytesPerSample = 144 rec_bytes_per_sample_ =
161 2 * channels; // 16 bits per sample in mono, 32 bits in stereo 145 2 * channels; // 16 bits per sample in mono, 32 bits in stereo
162 return 0; 146 return 0;
163 } 147 }
164 148
165 int32_t AudioDeviceBuffer::SetPlayoutChannels(size_t channels) { 149 int32_t AudioDeviceBuffer::SetPlayoutChannels(size_t channels) {
150 LOG(INFO) << "SetPlayoutChannels(" << channels << ")";
166 rtc::CritScope lock(&_critSect); 151 rtc::CritScope lock(&_critSect);
167 _playChannels = channels; 152 play_channels_ = channels;
168 // 16 bits per sample in mono, 32 bits in stereo 153 // 16 bits per sample in mono, 32 bits in stereo
169 _playBytesPerSample = 2 * channels; 154 play_bytes_per_sample_ = 2 * channels;
170 return 0; 155 return 0;
171 } 156 }
172 157
173 int32_t AudioDeviceBuffer::SetRecordingChannel( 158 int32_t AudioDeviceBuffer::SetRecordingChannel(
174 const AudioDeviceModule::ChannelType channel) { 159 const AudioDeviceModule::ChannelType channel) {
175 rtc::CritScope lock(&_critSect); 160 rtc::CritScope lock(&_critSect);
176 161
177 if (_recChannels == 1) { 162 if (rec_channels_ == 1) {
178 return -1; 163 return -1;
179 } 164 }
180 165
181 if (channel == AudioDeviceModule::kChannelBoth) { 166 if (channel == AudioDeviceModule::kChannelBoth) {
182 // two bytes per channel 167 // two bytes per channel
183 _recBytesPerSample = 4; 168 rec_bytes_per_sample_ = 4;
184 } else { 169 } else {
185 // only utilize one out of two possible channels (left or right) 170 // only utilize one out of two possible channels (left or right)
186 _recBytesPerSample = 2; 171 rec_bytes_per_sample_ = 2;
187 } 172 }
188 _recChannel = channel; 173 rec_channel_ = channel;
189 174
190 return 0; 175 return 0;
191 } 176 }
192 177
193 int32_t AudioDeviceBuffer::RecordingChannel( 178 int32_t AudioDeviceBuffer::RecordingChannel(
194 AudioDeviceModule::ChannelType& channel) const { 179 AudioDeviceModule::ChannelType& channel) const {
195 channel = _recChannel; 180 channel = rec_channel_;
196 return 0; 181 return 0;
197 } 182 }
198 183
199 size_t AudioDeviceBuffer::RecordingChannels() const { 184 size_t AudioDeviceBuffer::RecordingChannels() const {
200 return _recChannels; 185 return rec_channels_;
201 } 186 }
202 187
203 size_t AudioDeviceBuffer::PlayoutChannels() const { 188 size_t AudioDeviceBuffer::PlayoutChannels() const {
204 return _playChannels; 189 return play_channels_;
205 } 190 }
206 191
207 int32_t AudioDeviceBuffer::SetCurrentMicLevel(uint32_t level) { 192 int32_t AudioDeviceBuffer::SetCurrentMicLevel(uint32_t level) {
208 _currentMicLevel = level; 193 current_mic_level_ = level;
209 return 0; 194 return 0;
210 } 195 }
211 196
212 int32_t AudioDeviceBuffer::SetTypingStatus(bool typingStatus) { 197 int32_t AudioDeviceBuffer::SetTypingStatus(bool typing_status) {
213 _typingStatus = typingStatus; 198 typing_status_ = typing_status;
214 return 0; 199 return 0;
215 } 200 }
216 201
217 uint32_t AudioDeviceBuffer::NewMicLevel() const { 202 uint32_t AudioDeviceBuffer::NewMicLevel() const {
218 return _newMicLevel; 203 return new_mic_level_;
219 } 204 }
220 205
221 void AudioDeviceBuffer::SetVQEData(int playDelayMs, 206 void AudioDeviceBuffer::SetVQEData(int play_delay_ms,
222 int recDelayMs, 207 int rec_delay_ms,
223 int clockDrift) { 208 int clock_drift) {
224 if (high_delay_counter_ < kLogHighDelayIntervalFrames) { 209 play_delay_ms_ = play_delay_ms;
225 ++high_delay_counter_; 210 rec_delay_ms_ = rec_delay_ms;
226 } else { 211 clock_drift_ = clock_drift;
227 if (playDelayMs + recDelayMs > kHighDelayThresholdMs) {
228 high_delay_counter_ = 0;
229 LOG(LS_WARNING) << "High audio device delay reported (render="
230 << playDelayMs << " ms, capture=" << recDelayMs << " ms)";
231 }
232 }
233
234 _playDelayMS = playDelayMs;
235 _recDelayMS = recDelayMs;
236 _clockDrift = clockDrift;
237 } 212 }
238 213
239 int32_t AudioDeviceBuffer::StartInputFileRecording( 214 int32_t AudioDeviceBuffer::StartInputFileRecording(
240 const char fileName[kAdmMaxFileNameSize]) { 215 const char fileName[kAdmMaxFileNameSize]) {
241 rtc::CritScope lock(&_critSect); 216 LOG(LS_WARNING) << "Not implemented";
242 217 return 0;
243 _recFile.Flush();
244 _recFile.CloseFile();
245
246 return _recFile.OpenFile(fileName, false) ? 0 : -1;
247 } 218 }
248 219
249 int32_t AudioDeviceBuffer::StopInputFileRecording() { 220 int32_t AudioDeviceBuffer::StopInputFileRecording() {
250 rtc::CritScope lock(&_critSect); 221 LOG(LS_WARNING) << "Not implemented";
251
252 _recFile.Flush();
253 _recFile.CloseFile();
254
255 return 0; 222 return 0;
256 } 223 }
257 224
258 int32_t AudioDeviceBuffer::StartOutputFileRecording( 225 int32_t AudioDeviceBuffer::StartOutputFileRecording(
259 const char fileName[kAdmMaxFileNameSize]) { 226 const char fileName[kAdmMaxFileNameSize]) {
260 rtc::CritScope lock(&_critSect); 227 LOG(LS_WARNING) << "Not implemented";
261 228 return 0;
262 _playFile.Flush();
263 _playFile.CloseFile();
264
265 return _playFile.OpenFile(fileName, false) ? 0 : -1;
266 } 229 }
267 230
268 int32_t AudioDeviceBuffer::StopOutputFileRecording() { 231 int32_t AudioDeviceBuffer::StopOutputFileRecording() {
269 rtc::CritScope lock(&_critSect); 232 LOG(LS_WARNING) << "Not implemented";
270
271 _playFile.Flush();
272 _playFile.CloseFile();
273
274 return 0; 233 return 0;
275 } 234 }
276 235
277 int32_t AudioDeviceBuffer::SetRecordedBuffer(const void* audioBuffer, 236 int32_t AudioDeviceBuffer::SetRecordedBuffer(const void* audio_buffer,
278 size_t nSamples) { 237 size_t num_samples) {
238 AllocateRecordingBufferIfNeeded();
239 RTC_CHECK(rec_buffer_);
240 // WebRTC can only receive audio in 10ms chunks, hence we fail if the native
241 // audio layer tries to deliver something else.
242 RTC_CHECK_EQ(num_samples, rec_samples_per_10ms_);
243
279 rtc::CritScope lock(&_critSect); 244 rtc::CritScope lock(&_critSect);
280 245
281 if (_recBytesPerSample == 0) { 246 if (rec_channel_ == AudioDeviceModule::kChannelBoth) {
282 assert(false); 247 // Copy the complete input buffer to the local buffer.
283 return -1; 248 memcpy(&rec_buffer_[0], audio_buffer, rec_bytes_per_10ms_);
284 }
285
286 _recSamples = nSamples;
287 _recSize = _recBytesPerSample * nSamples; // {2,4}*nSamples
288 if (_recSize > kMaxBufferSizeBytes) {
289 assert(false);
290 return -1;
291 }
292
293 if (_recChannel == AudioDeviceModule::kChannelBoth) {
294 // (default) copy the complete input buffer to the local buffer
295 memcpy(&_recBuffer[0], audioBuffer, _recSize);
296 } else { 249 } else {
297 int16_t* ptr16In = (int16_t*)audioBuffer; 250 int16_t* ptr16In = (int16_t*)audio_buffer;
298 int16_t* ptr16Out = (int16_t*)&_recBuffer[0]; 251 int16_t* ptr16Out = (int16_t*)&rec_buffer_[0];
299 252 if (AudioDeviceModule::kChannelRight == rec_channel_) {
300 if (AudioDeviceModule::kChannelRight == _recChannel) {
301 ptr16In++; 253 ptr16In++;
302 } 254 }
303 255 // Exctract left or right channel from input buffer to the local buffer.
304 // exctract left or right channel from input buffer to the local buffer 256 for (size_t i = 0; i < rec_samples_per_10ms_; i++) {
305 for (size_t i = 0; i < _recSamples; i++) {
306 *ptr16Out = *ptr16In; 257 *ptr16Out = *ptr16In;
307 ptr16Out++; 258 ptr16Out++;
308 ptr16In++; 259 ptr16In++;
309 ptr16In++; 260 ptr16In++;
310 } 261 }
311 } 262 }
312 263
313 if (_recFile.is_open()) {
314 // write to binary file in mono or stereo (interleaved)
315 _recFile.Write(&_recBuffer[0], _recSize);
316 }
317
318 // Update some stats but do it on the task queue to ensure that the members 264 // Update some stats but do it on the task queue to ensure that the members
319 // are modified and read on the same thread. 265 // are modified and read on the same thread.
320 task_queue_.PostTask( 266 task_queue_.PostTask(
321 rtc::Bind(&AudioDeviceBuffer::UpdateRecStats, this, nSamples)); 267 rtc::Bind(&AudioDeviceBuffer::UpdateRecStats, this, num_samples));
322
323 return 0; 268 return 0;
324 } 269 }
325 270
326 int32_t AudioDeviceBuffer::DeliverRecordedData() { 271 int32_t AudioDeviceBuffer::DeliverRecordedData() {
272 RTC_CHECK(rec_buffer_);
273 RTC_DCHECK(audio_transport_cb_);
327 rtc::CritScope lock(&_critSectCb); 274 rtc::CritScope lock(&_critSectCb);
328 // Ensure that user has initialized all essential members
329 if ((_recSampleRate == 0) || (_recSamples == 0) ||
330 (_recBytesPerSample == 0) || (_recChannels == 0)) {
331 RTC_NOTREACHED();
332 return -1;
333 }
334 275
335 if (!_ptrCbAudioTransport) { 276 if (!audio_transport_cb_) {
336 LOG(LS_WARNING) << "Invalid audio transport"; 277 LOG(LS_WARNING) << "Invalid audio transport";
337 return 0; 278 return 0;
338 } 279 }
339 280
340 int32_t res(0); 281 int32_t res(0);
341 uint32_t newMicLevel(0); 282 uint32_t newMicLevel(0);
342 uint32_t totalDelayMS = _playDelayMS + _recDelayMS; 283 uint32_t totalDelayMS = play_delay_ms_ + rec_delay_ms_;
343 res = _ptrCbAudioTransport->RecordedDataIsAvailable( 284 res = audio_transport_cb_->RecordedDataIsAvailable(
344 &_recBuffer[0], _recSamples, _recBytesPerSample, _recChannels, 285 &rec_buffer_[0], rec_samples_per_10ms_, rec_bytes_per_sample_,
345 _recSampleRate, totalDelayMS, _clockDrift, _currentMicLevel, 286 rec_channels_, rec_sample_rate_, totalDelayMS, clock_drift_,
346 _typingStatus, newMicLevel); 287 current_mic_level_, typing_status_, newMicLevel);
347 if (res != -1) { 288 if (res != -1) {
348 _newMicLevel = newMicLevel; 289 new_mic_level_ = newMicLevel;
290 } else {
291 LOG(LS_ERROR) << "RecordedDataIsAvailable() failed";
349 } 292 }
350 293
351 return 0; 294 return 0;
352 } 295 }
353 296
354 int32_t AudioDeviceBuffer::RequestPlayoutData(size_t nSamples) { 297 int32_t AudioDeviceBuffer::RequestPlayoutData(size_t num_samples) {
355 uint32_t playSampleRate = 0;
356 size_t playBytesPerSample = 0;
357 size_t playChannels = 0;
358
359 // Measure time since last function call and update an array where the 298 // Measure time since last function call and update an array where the
360 // position/index corresponds to time differences (in milliseconds) between 299 // position/index corresponds to time differences (in milliseconds) between
361 // two successive playout callbacks, and the stored value is the number of 300 // two successive playout callbacks, and the stored value is the number of
362 // times a given time difference was found. 301 // times a given time difference was found.
363 int64_t now_time = rtc::TimeMillis(); 302 int64_t now_time = rtc::TimeMillis();
364 size_t diff_time = rtc::TimeDiff(now_time, last_playout_time_); 303 size_t diff_time = rtc::TimeDiff(now_time, last_playout_time_);
365 // Truncate at 500ms to limit the size of the array. 304 // Truncate at 500ms to limit the size of the array.
366 diff_time = std::min(kMaxDeltaTimeInMs, diff_time); 305 diff_time = std::min(kMaxDeltaTimeInMs, diff_time);
367 last_playout_time_ = now_time; 306 last_playout_time_ = now_time;
368 playout_diff_times_[diff_time]++; 307 playout_diff_times_[diff_time]++;
369 308
370 // TOOD(henrika): improve bad locking model and make it more clear that only 309 AllocatePlayoutBufferIfNeeded();
371 // 10ms buffer sizes is supported in WebRTC. 310 RTC_CHECK(play_buffer_);
372 { 311 // WebRTC can only provide audio in 10ms chunks, hence we fail if the native
373 rtc::CritScope lock(&_critSect); 312 // audio layer asks for something else.
374 313 RTC_CHECK_EQ(num_samples, play_samples_per_10ms_);
375 // Store copies under lock and use copies hereafter to avoid race with
376 // setter methods.
377 playSampleRate = _playSampleRate;
378 playBytesPerSample = _playBytesPerSample;
379 playChannels = _playChannels;
380
381 // Ensure that user has initialized all essential members
382 if ((playBytesPerSample == 0) || (playChannels == 0) ||
383 (playSampleRate == 0)) {
384 RTC_NOTREACHED();
385 return -1;
386 }
387
388 _playSamples = nSamples;
389 _playSize = playBytesPerSample * nSamples; // {2,4}*nSamples
390 RTC_CHECK_LE(_playSize, kMaxBufferSizeBytes);
391 RTC_CHECK_EQ(nSamples, _playSamples);
392 }
393
394 size_t nSamplesOut(0);
395 314
396 rtc::CritScope lock(&_critSectCb); 315 rtc::CritScope lock(&_critSectCb);
397 316
398 // It is currently supported to start playout without a valid audio 317 // It is currently supported to start playout without a valid audio
399 // transport object. Leads to warning and silence. 318 // transport object. Leads to warning and silence.
400 if (!_ptrCbAudioTransport) { 319 if (!audio_transport_cb_) {
401 LOG(LS_WARNING) << "Invalid audio transport"; 320 LOG(LS_WARNING) << "Invalid audio transport";
402 return 0; 321 return 0;
403 } 322 }
404 323
405 uint32_t res(0); 324 uint32_t res(0);
406 int64_t elapsed_time_ms = -1; 325 int64_t elapsed_time_ms = -1;
407 int64_t ntp_time_ms = -1; 326 int64_t ntp_time_ms = -1;
408 res = _ptrCbAudioTransport->NeedMorePlayData( 327 size_t num_samples_out(0);
409 _playSamples, playBytesPerSample, playChannels, playSampleRate, 328 res = audio_transport_cb_->NeedMorePlayData(
410 &_playBuffer[0], nSamplesOut, &elapsed_time_ms, &ntp_time_ms); 329 play_samples_per_10ms_, play_bytes_per_sample_, play_channels_,
330 play_sample_rate_, &play_buffer_[0], num_samples_out, &elapsed_time_ms,
331 &ntp_time_ms);
411 if (res != 0) { 332 if (res != 0) {
412 LOG(LS_ERROR) << "NeedMorePlayData() failed"; 333 LOG(LS_ERROR) << "NeedMorePlayData() failed";
413 } 334 }
414 335
415 // Update some stats but do it on the task queue to ensure that access of 336 // Update some stats but do it on the task queue to ensure that access of
416 // members is serialized hence avoiding usage of locks. 337 // members is serialized hence avoiding usage of locks.
417 task_queue_.PostTask( 338 task_queue_.PostTask(
418 rtc::Bind(&AudioDeviceBuffer::UpdatePlayStats, this, nSamplesOut)); 339 rtc::Bind(&AudioDeviceBuffer::UpdatePlayStats, this, num_samples_out));
419 340 return static_cast<int32_t>(num_samples_out);
420 return static_cast<int32_t>(nSamplesOut);
421 } 341 }
422 342
423 int32_t AudioDeviceBuffer::GetPlayoutData(void* audioBuffer) { 343 int32_t AudioDeviceBuffer::GetPlayoutData(void* audio_buffer) {
424 rtc::CritScope lock(&_critSect); 344 rtc::CritScope lock(&_critSect);
425 RTC_CHECK_LE(_playSize, kMaxBufferSizeBytes); 345 memcpy(audio_buffer, &play_buffer_[0], play_bytes_per_10ms_);
346 return static_cast<int32_t>(play_samples_per_10ms_);
347 }
426 348
427 memcpy(audioBuffer, &_playBuffer[0], _playSize); 349 void AudioDeviceBuffer::AllocatePlayoutBufferIfNeeded() {
350 RTC_CHECK(play_bytes_per_sample_);
351 if (play_buffer_)
352 return;
353 LOG(INFO) << __FUNCTION__;
354 rtc::CritScope lock(&_critSect);
355 // Derive the required buffer size given sample rate and number of channels.
356 play_samples_per_10ms_ = static_cast<size_t>(play_sample_rate_ * 10 / 1000);
357 play_bytes_per_10ms_ = play_bytes_per_sample_ * play_samples_per_10ms_;
358 LOG(INFO) << "playout samples per 10ms: " << play_samples_per_10ms_;
359 LOG(INFO) << "playout bytes per 10ms: " << play_bytes_per_10ms_;
360 // Allocate memory for the playout audio buffer. It will always contain audio
361 // samples corresponding to 10ms of audio to be played out.
362 play_buffer_.reset(new int8_t[play_bytes_per_10ms_]);
363 }
428 364
429 if (_playFile.is_open()) { 365 void AudioDeviceBuffer::AllocateRecordingBufferIfNeeded() {
430 // write to binary file in mono or stereo (interleaved) 366 RTC_CHECK(rec_bytes_per_sample_);
431 _playFile.Write(&_playBuffer[0], _playSize); 367 if (rec_buffer_)
432 } 368 return;
433 369 LOG(INFO) << __FUNCTION__;
434 return static_cast<int32_t>(_playSamples); 370 rtc::CritScope lock(&_critSect);
371 // Derive the required buffer size given sample rate and number of channels.
372 rec_samples_per_10ms_ = static_cast<size_t>(rec_sample_rate_ * 10 / 1000);
373 rec_bytes_per_10ms_ = rec_bytes_per_sample_ * rec_samples_per_10ms_;
374 LOG(INFO) << "recorded samples per 10ms: " << rec_samples_per_10ms_;
375 LOG(INFO) << "recorded bytes per 10ms: " << rec_bytes_per_10ms_;
376 // Allocate memory for the recording audio buffer. It will always contain
377 // audio samples corresponding to 10ms of audio.
378 rec_buffer_.reset(new int8_t[rec_bytes_per_10ms_]);
435 } 379 }
436 380
437 void AudioDeviceBuffer::StartTimer() { 381 void AudioDeviceBuffer::StartTimer() {
438 last_log_stat_time_ = rtc::TimeMillis(); 382 last_log_stat_time_ = rtc::TimeMillis();
439 task_queue_.PostDelayedTask(rtc::Bind(&AudioDeviceBuffer::LogStats, this), 383 task_queue_.PostDelayedTask(rtc::Bind(&AudioDeviceBuffer::LogStats, this),
440 kTimerIntervalInMilliseconds); 384 kTimerIntervalInMilliseconds);
441 } 385 }
442 386
443 void AudioDeviceBuffer::LogStats() { 387 void AudioDeviceBuffer::LogStats() {
444 RTC_DCHECK(task_queue_.IsCurrent()); 388 RTC_DCHECK(task_queue_.IsCurrent());
445 389
446 int64_t now_time = rtc::TimeMillis(); 390 int64_t now_time = rtc::TimeMillis();
447 int64_t next_callback_time = now_time + kTimerIntervalInMilliseconds; 391 int64_t next_callback_time = now_time + kTimerIntervalInMilliseconds;
448 int64_t time_since_last = rtc::TimeDiff(now_time, last_log_stat_time_); 392 int64_t time_since_last = rtc::TimeDiff(now_time, last_log_stat_time_);
449 last_log_stat_time_ = now_time; 393 last_log_stat_time_ = now_time;
450 394
451 // Log the latest statistics but skip the first 10 seconds since we are not 395 // Log the latest statistics but skip the first 10 seconds since we are not
452 // sure of the exact starting point. I.e., the first log printout will be 396 // sure of the exact starting point. I.e., the first log printout will be
453 // after ~20 seconds. 397 // after ~20 seconds.
454 if (++num_stat_reports_ > 1) { 398 if (++num_stat_reports_ > 1) {
455 uint32_t diff_samples = rec_samples_ - last_rec_samples_; 399 uint32_t diff_samples = rec_samples_ - last_rec_samples_;
456 uint32_t rate = diff_samples / kTimerIntervalInSeconds; 400 uint32_t rate = diff_samples / kTimerIntervalInSeconds;
457 LOG(INFO) << "[REC : " << time_since_last << "msec, " 401 LOG(INFO) << "[REC : " << time_since_last << "msec, "
458 << _recSampleRate / 1000 402 << rec_sample_rate_ / 1000
459 << "kHz] callbacks: " << rec_callbacks_ - last_rec_callbacks_ 403 << "kHz] callbacks: " << rec_callbacks_ - last_rec_callbacks_
460 << ", " 404 << ", "
461 << "samples: " << diff_samples << ", " 405 << "samples: " << diff_samples << ", "
462 << "rate: " << rate; 406 << "rate: " << rate;
463 407
464 diff_samples = play_samples_ - last_play_samples_; 408 diff_samples = play_samples_ - last_play_samples_;
465 rate = diff_samples / kTimerIntervalInSeconds; 409 rate = diff_samples / kTimerIntervalInSeconds;
466 LOG(INFO) << "[PLAY: " << time_since_last << "msec, " 410 LOG(INFO) << "[PLAY: " << time_since_last << "msec, "
467 << _playSampleRate / 1000 411 << play_sample_rate_ / 1000
468 << "kHz] callbacks: " << play_callbacks_ - last_play_callbacks_ 412 << "kHz] callbacks: " << play_callbacks_ - last_play_callbacks_
469 << ", " 413 << ", "
470 << "samples: " << diff_samples << ", " 414 << "samples: " << diff_samples << ", "
471 << "rate: " << rate; 415 << "rate: " << rate;
472 } 416 }
473 417
474 last_rec_callbacks_ = rec_callbacks_; 418 last_rec_callbacks_ = rec_callbacks_;
475 last_play_callbacks_ = play_callbacks_; 419 last_play_callbacks_ = play_callbacks_;
476 last_rec_samples_ = rec_samples_; 420 last_rec_samples_ = rec_samples_;
477 last_play_samples_ = play_samples_; 421 last_play_samples_ = play_samples_;
(...skipping 13 matching lines...) Expand all
491 rec_samples_ += num_samples; 435 rec_samples_ += num_samples;
492 } 436 }
493 437
494 void AudioDeviceBuffer::UpdatePlayStats(size_t num_samples) { 438 void AudioDeviceBuffer::UpdatePlayStats(size_t num_samples) {
495 RTC_DCHECK(task_queue_.IsCurrent()); 439 RTC_DCHECK(task_queue_.IsCurrent());
496 ++play_callbacks_; 440 ++play_callbacks_;
497 play_samples_ += num_samples; 441 play_samples_ += num_samples;
498 } 442 }
499 443
500 } // namespace webrtc 444 } // namespace webrtc
OLDNEW
« no previous file with comments | « webrtc/modules/audio_device/audio_device_buffer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698