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

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

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