blob: ba8b6a5b3e1f773be7acc0a55a98ec7a77b7fe1a [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
xians@webrtc.org20aabbb2012-02-20 09:17:41 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
henrika3d7346f2016-07-29 16:20:47 +020011#include <algorithm>
12
pbos@webrtc.org811269d2013-07-11 13:24:38 +000013#include "webrtc/modules/audio_device/audio_device_buffer.h"
andrew@webrtc.org25534502013-09-13 00:02:13 +000014
henrika3d7346f2016-07-29 16:20:47 +020015#include "webrtc/base/arraysize.h"
henrika6c4d0f02016-07-14 05:54:19 -070016#include "webrtc/base/bind.h"
henrika3f33e2a2016-07-06 00:33:57 -070017#include "webrtc/base/checks.h"
18#include "webrtc/base/logging.h"
Peter Kastingdce40cf2015-08-24 14:52:23 -070019#include "webrtc/base/format_macros.h"
henrika6c4d0f02016-07-14 05:54:19 -070020#include "webrtc/base/timeutils.h"
pbos@webrtc.org811269d2013-07-11 13:24:38 +000021#include "webrtc/modules/audio_device/audio_device_config.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000022
niklase@google.com470e71d2011-07-07 08:21:25 +000023namespace webrtc {
24
andrew@webrtc.org8f940132013-09-11 22:35:00 +000025static const int kHighDelayThresholdMs = 300;
26static const int kLogHighDelayIntervalFrames = 500; // 5 seconds.
27
henrika6c4d0f02016-07-14 05:54:19 -070028static const char kTimerQueueName[] = "AudioDeviceBufferTimer";
29
30// Time between two sucessive calls to LogStats().
31static const size_t kTimerIntervalInSeconds = 10;
32static const size_t kTimerIntervalInMilliseconds =
33 kTimerIntervalInSeconds * rtc::kNumMillisecsPerSec;
34
henrika0fd68012016-07-04 13:01:19 +020035AudioDeviceBuffer::AudioDeviceBuffer()
henrika6c4d0f02016-07-14 05:54:19 -070036 : _ptrCbAudioTransport(nullptr),
37 task_queue_(kTimerQueueName),
38 timer_has_started_(false),
henrika0fd68012016-07-04 13:01:19 +020039 _recSampleRate(0),
40 _playSampleRate(0),
41 _recChannels(0),
42 _playChannels(0),
43 _recChannel(AudioDeviceModule::kChannelBoth),
44 _recBytesPerSample(0),
45 _playBytesPerSample(0),
46 _recSamples(0),
47 _recSize(0),
48 _playSamples(0),
49 _playSize(0),
50 _recFile(*FileWrapper::Create()),
51 _playFile(*FileWrapper::Create()),
52 _currentMicLevel(0),
53 _newMicLevel(0),
54 _typingStatus(false),
55 _playDelayMS(0),
56 _recDelayMS(0),
57 _clockDrift(0),
58 // Set to the interval in order to log on the first occurrence.
henrika6c4d0f02016-07-14 05:54:19 -070059 high_delay_counter_(kLogHighDelayIntervalFrames),
60 num_stat_reports_(0),
61 rec_callbacks_(0),
62 last_rec_callbacks_(0),
63 play_callbacks_(0),
64 last_play_callbacks_(0),
65 rec_samples_(0),
66 last_rec_samples_(0),
67 play_samples_(0),
68 last_play_samples_(0),
69 last_log_stat_time_(0) {
henrika3f33e2a2016-07-06 00:33:57 -070070 LOG(INFO) << "AudioDeviceBuffer::ctor";
henrika0fd68012016-07-04 13:01:19 +020071 memset(_recBuffer, 0, kMaxBufferSizeBytes);
72 memset(_playBuffer, 0, kMaxBufferSizeBytes);
niklase@google.com470e71d2011-07-07 08:21:25 +000073}
74
henrika0fd68012016-07-04 13:01:19 +020075AudioDeviceBuffer::~AudioDeviceBuffer() {
henrika6c4d0f02016-07-14 05:54:19 -070076 RTC_DCHECK(thread_checker_.CalledOnValidThread());
henrika3f33e2a2016-07-06 00:33:57 -070077 LOG(INFO) << "AudioDeviceBuffer::~dtor";
henrika3d7346f2016-07-29 16:20:47 +020078
79 size_t total_diff_time = 0;
80 int num_measurements = 0;
81 LOG(INFO) << "[playout diff time => #measurements]";
82 for (size_t diff = 0; diff < arraysize(playout_diff_times_); ++diff) {
83 uint32_t num_elements = playout_diff_times_[diff];
84 if (num_elements > 0) {
85 total_diff_time += num_elements * diff;
86 num_measurements += num_elements;
87 LOG(INFO) << "[" << diff << " => " << num_elements << "]";
88 }
89 }
90 if (num_measurements > 0) {
91 LOG(INFO) << "total_diff_time: " << total_diff_time;
92 LOG(INFO) << "num_measurements: " << num_measurements;
93 LOG(INFO) << "average: "
94 << static_cast<float>(total_diff_time) / num_measurements;
95 }
96
henrika6c4d0f02016-07-14 05:54:19 -070097 _recFile.Flush();
98 _recFile.CloseFile();
99 delete &_recFile;
niklase@google.com470e71d2011-07-07 08:21:25 +0000100
henrika6c4d0f02016-07-14 05:54:19 -0700101 _playFile.Flush();
102 _playFile.CloseFile();
103 delete &_playFile;
niklase@google.com470e71d2011-07-07 08:21:25 +0000104}
105
henrika0fd68012016-07-04 13:01:19 +0200106int32_t AudioDeviceBuffer::RegisterAudioCallback(
107 AudioTransport* audioCallback) {
henrika3f33e2a2016-07-06 00:33:57 -0700108 LOG(INFO) << __FUNCTION__;
henrika6c4d0f02016-07-14 05:54:19 -0700109 rtc::CritScope lock(&_critSectCb);
henrika0fd68012016-07-04 13:01:19 +0200110 _ptrCbAudioTransport = audioCallback;
henrika0fd68012016-07-04 13:01:19 +0200111 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000112}
113
henrika0fd68012016-07-04 13:01:19 +0200114int32_t AudioDeviceBuffer::InitPlayout() {
henrika6c4d0f02016-07-14 05:54:19 -0700115 RTC_DCHECK(thread_checker_.CalledOnValidThread());
henrika3f33e2a2016-07-06 00:33:57 -0700116 LOG(INFO) << __FUNCTION__;
henrika3d7346f2016-07-29 16:20:47 +0200117 last_playout_time_ = rtc::TimeMillis();
henrika6c4d0f02016-07-14 05:54:19 -0700118 if (!timer_has_started_) {
119 StartTimer();
120 timer_has_started_ = true;
121 }
henrika0fd68012016-07-04 13:01:19 +0200122 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000123}
124
henrika0fd68012016-07-04 13:01:19 +0200125int32_t AudioDeviceBuffer::InitRecording() {
henrika6c4d0f02016-07-14 05:54:19 -0700126 RTC_DCHECK(thread_checker_.CalledOnValidThread());
henrika3f33e2a2016-07-06 00:33:57 -0700127 LOG(INFO) << __FUNCTION__;
henrika6c4d0f02016-07-14 05:54:19 -0700128 if (!timer_has_started_) {
129 StartTimer();
130 timer_has_started_ = true;
131 }
henrika0fd68012016-07-04 13:01:19 +0200132 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000133}
134
henrika0fd68012016-07-04 13:01:19 +0200135int32_t AudioDeviceBuffer::SetRecordingSampleRate(uint32_t fsHz) {
henrika3f33e2a2016-07-06 00:33:57 -0700136 LOG(INFO) << "SetRecordingSampleRate(" << fsHz << ")";
henrika6c4d0f02016-07-14 05:54:19 -0700137 rtc::CritScope lock(&_critSect);
henrika0fd68012016-07-04 13:01:19 +0200138 _recSampleRate = fsHz;
139 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000140}
141
henrika0fd68012016-07-04 13:01:19 +0200142int32_t AudioDeviceBuffer::SetPlayoutSampleRate(uint32_t fsHz) {
henrika3f33e2a2016-07-06 00:33:57 -0700143 LOG(INFO) << "SetPlayoutSampleRate(" << fsHz << ")";
henrika6c4d0f02016-07-14 05:54:19 -0700144 rtc::CritScope lock(&_critSect);
henrika0fd68012016-07-04 13:01:19 +0200145 _playSampleRate = fsHz;
146 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000147}
148
henrika0fd68012016-07-04 13:01:19 +0200149int32_t AudioDeviceBuffer::RecordingSampleRate() const {
150 return _recSampleRate;
niklase@google.com470e71d2011-07-07 08:21:25 +0000151}
152
henrika0fd68012016-07-04 13:01:19 +0200153int32_t AudioDeviceBuffer::PlayoutSampleRate() const {
154 return _playSampleRate;
niklase@google.com470e71d2011-07-07 08:21:25 +0000155}
156
henrika0fd68012016-07-04 13:01:19 +0200157int32_t AudioDeviceBuffer::SetRecordingChannels(size_t channels) {
henrika6c4d0f02016-07-14 05:54:19 -0700158 rtc::CritScope lock(&_critSect);
henrika0fd68012016-07-04 13:01:19 +0200159 _recChannels = channels;
160 _recBytesPerSample =
161 2 * channels; // 16 bits per sample in mono, 32 bits in stereo
162 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000163}
164
henrika0fd68012016-07-04 13:01:19 +0200165int32_t AudioDeviceBuffer::SetPlayoutChannels(size_t channels) {
henrika6c4d0f02016-07-14 05:54:19 -0700166 rtc::CritScope lock(&_critSect);
henrika0fd68012016-07-04 13:01:19 +0200167 _playChannels = channels;
168 // 16 bits per sample in mono, 32 bits in stereo
169 _playBytesPerSample = 2 * channels;
170 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000171}
172
henrika0fd68012016-07-04 13:01:19 +0200173int32_t AudioDeviceBuffer::SetRecordingChannel(
174 const AudioDeviceModule::ChannelType channel) {
henrika6c4d0f02016-07-14 05:54:19 -0700175 rtc::CritScope lock(&_critSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000176
henrika0fd68012016-07-04 13:01:19 +0200177 if (_recChannels == 1) {
178 return -1;
179 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000180
henrika0fd68012016-07-04 13:01:19 +0200181 if (channel == AudioDeviceModule::kChannelBoth) {
182 // two bytes per channel
183 _recBytesPerSample = 4;
184 } else {
185 // only utilize one out of two possible channels (left or right)
186 _recBytesPerSample = 2;
187 }
188 _recChannel = channel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000189
henrika0fd68012016-07-04 13:01:19 +0200190 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000191}
192
henrika0fd68012016-07-04 13:01:19 +0200193int32_t AudioDeviceBuffer::RecordingChannel(
194 AudioDeviceModule::ChannelType& channel) const {
195 channel = _recChannel;
196 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000197}
198
henrika0fd68012016-07-04 13:01:19 +0200199size_t AudioDeviceBuffer::RecordingChannels() const {
200 return _recChannels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000201}
202
henrika0fd68012016-07-04 13:01:19 +0200203size_t AudioDeviceBuffer::PlayoutChannels() const {
204 return _playChannels;
niklase@google.com470e71d2011-07-07 08:21:25 +0000205}
206
henrika0fd68012016-07-04 13:01:19 +0200207int32_t AudioDeviceBuffer::SetCurrentMicLevel(uint32_t level) {
208 _currentMicLevel = level;
209 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000210}
211
henrika0fd68012016-07-04 13:01:19 +0200212int32_t AudioDeviceBuffer::SetTypingStatus(bool typingStatus) {
213 _typingStatus = typingStatus;
214 return 0;
niklas.enbom@webrtc.org3be565b2013-05-07 21:04:24 +0000215}
216
henrika0fd68012016-07-04 13:01:19 +0200217uint32_t AudioDeviceBuffer::NewMicLevel() const {
218 return _newMicLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000219}
220
henrika0fd68012016-07-04 13:01:19 +0200221void AudioDeviceBuffer::SetVQEData(int playDelayMs,
222 int recDelayMs,
andrew@webrtc.org5eb997a2013-09-12 01:01:42 +0000223 int clockDrift) {
andrew@webrtc.org8f940132013-09-11 22:35:00 +0000224 if (high_delay_counter_ < kLogHighDelayIntervalFrames) {
225 ++high_delay_counter_;
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)";
niklase@google.com470e71d2011-07-07 08:21:25 +0000231 }
andrew@webrtc.org8f940132013-09-11 22:35:00 +0000232 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000233
andrew@webrtc.org8f940132013-09-11 22:35:00 +0000234 _playDelayMS = playDelayMs;
235 _recDelayMS = recDelayMs;
236 _clockDrift = clockDrift;
niklase@google.com470e71d2011-07-07 08:21:25 +0000237}
238
pbos@webrtc.org25509882013-04-09 10:30:35 +0000239int32_t AudioDeviceBuffer::StartInputFileRecording(
henrika0fd68012016-07-04 13:01:19 +0200240 const char fileName[kAdmMaxFileNameSize]) {
henrika6c4d0f02016-07-14 05:54:19 -0700241 rtc::CritScope lock(&_critSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000242
henrika0fd68012016-07-04 13:01:19 +0200243 _recFile.Flush();
244 _recFile.CloseFile();
niklase@google.com470e71d2011-07-07 08:21:25 +0000245
henrika0fd68012016-07-04 13:01:19 +0200246 return _recFile.OpenFile(fileName, false) ? 0 : -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000247}
248
henrika0fd68012016-07-04 13:01:19 +0200249int32_t AudioDeviceBuffer::StopInputFileRecording() {
henrika6c4d0f02016-07-14 05:54:19 -0700250 rtc::CritScope lock(&_critSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000251
henrika0fd68012016-07-04 13:01:19 +0200252 _recFile.Flush();
253 _recFile.CloseFile();
niklase@google.com470e71d2011-07-07 08:21:25 +0000254
henrika0fd68012016-07-04 13:01:19 +0200255 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000256}
257
pbos@webrtc.org25509882013-04-09 10:30:35 +0000258int32_t AudioDeviceBuffer::StartOutputFileRecording(
henrika0fd68012016-07-04 13:01:19 +0200259 const char fileName[kAdmMaxFileNameSize]) {
henrika6c4d0f02016-07-14 05:54:19 -0700260 rtc::CritScope lock(&_critSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000261
henrika0fd68012016-07-04 13:01:19 +0200262 _playFile.Flush();
263 _playFile.CloseFile();
niklase@google.com470e71d2011-07-07 08:21:25 +0000264
henrika0fd68012016-07-04 13:01:19 +0200265 return _playFile.OpenFile(fileName, false) ? 0 : -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000266}
267
henrika0fd68012016-07-04 13:01:19 +0200268int32_t AudioDeviceBuffer::StopOutputFileRecording() {
henrika6c4d0f02016-07-14 05:54:19 -0700269 rtc::CritScope lock(&_critSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000270
henrika0fd68012016-07-04 13:01:19 +0200271 _playFile.Flush();
272 _playFile.CloseFile();
niklase@google.com470e71d2011-07-07 08:21:25 +0000273
henrika0fd68012016-07-04 13:01:19 +0200274 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000275}
276
pbos@webrtc.org25509882013-04-09 10:30:35 +0000277int32_t AudioDeviceBuffer::SetRecordedBuffer(const void* audioBuffer,
henrika0fd68012016-07-04 13:01:19 +0200278 size_t nSamples) {
henrika6c4d0f02016-07-14 05:54:19 -0700279 rtc::CritScope lock(&_critSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000280
henrika0fd68012016-07-04 13:01:19 +0200281 if (_recBytesPerSample == 0) {
282 assert(false);
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);
296 } else {
297 int16_t* ptr16In = (int16_t*)audioBuffer;
298 int16_t* ptr16Out = (int16_t*)&_recBuffer[0];
299
300 if (AudioDeviceModule::kChannelRight == _recChannel) {
301 ptr16In++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000302 }
303
henrika0fd68012016-07-04 13:01:19 +0200304 // exctract left or right channel from input buffer to the local buffer
305 for (size_t i = 0; i < _recSamples; i++) {
306 *ptr16Out = *ptr16In;
307 ptr16Out++;
308 ptr16In++;
309 ptr16In++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000310 }
henrika0fd68012016-07-04 13:01:19 +0200311 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000312
henrika0fd68012016-07-04 13:01:19 +0200313 if (_recFile.is_open()) {
314 // write to binary file in mono or stereo (interleaved)
315 _recFile.Write(&_recBuffer[0], _recSize);
316 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000317
henrika6c4d0f02016-07-14 05:54:19 -0700318 // Update some stats but do it on the task queue to ensure that the members
319 // are modified and read on the same thread.
320 task_queue_.PostTask(
321 rtc::Bind(&AudioDeviceBuffer::UpdateRecStats, this, nSamples));
322
henrika0fd68012016-07-04 13:01:19 +0200323 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000324}
325
henrika0fd68012016-07-04 13:01:19 +0200326int32_t AudioDeviceBuffer::DeliverRecordedData() {
henrika6c4d0f02016-07-14 05:54:19 -0700327 rtc::CritScope lock(&_critSectCb);
henrika0fd68012016-07-04 13:01:19 +0200328 // Ensure that user has initialized all essential members
329 if ((_recSampleRate == 0) || (_recSamples == 0) ||
330 (_recBytesPerSample == 0) || (_recChannels == 0)) {
henrika3f33e2a2016-07-06 00:33:57 -0700331 RTC_NOTREACHED();
henrika0fd68012016-07-04 13:01:19 +0200332 return -1;
333 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000334
henrika3f33e2a2016-07-06 00:33:57 -0700335 if (!_ptrCbAudioTransport) {
336 LOG(LS_WARNING) << "Invalid audio transport";
niklase@google.com470e71d2011-07-07 08:21:25 +0000337 return 0;
henrika0fd68012016-07-04 13:01:19 +0200338 }
339
340 int32_t res(0);
341 uint32_t newMicLevel(0);
342 uint32_t totalDelayMS = _playDelayMS + _recDelayMS;
henrika0fd68012016-07-04 13:01:19 +0200343 res = _ptrCbAudioTransport->RecordedDataIsAvailable(
344 &_recBuffer[0], _recSamples, _recBytesPerSample, _recChannels,
345 _recSampleRate, totalDelayMS, _clockDrift, _currentMicLevel,
346 _typingStatus, newMicLevel);
347 if (res != -1) {
348 _newMicLevel = newMicLevel;
349 }
350
351 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000352}
353
henrika0fd68012016-07-04 13:01:19 +0200354int32_t AudioDeviceBuffer::RequestPlayoutData(size_t nSamples) {
355 uint32_t playSampleRate = 0;
356 size_t playBytesPerSample = 0;
357 size_t playChannels = 0;
henrika3f33e2a2016-07-06 00:33:57 -0700358
henrika3d7346f2016-07-29 16:20:47 +0200359 // Measure time since last function call and update an array where the
360 // position/index corresponds to time differences (in milliseconds) between
361 // two successive playout callbacks, and the stored value is the number of
362 // times a given time difference was found.
363 int64_t now_time = rtc::TimeMillis();
364 size_t diff_time = rtc::TimeDiff(now_time, last_playout_time_);
365 // Truncate at 500ms to limit the size of the array.
366 diff_time = std::min(kMaxDeltaTimeInMs, diff_time);
367 last_playout_time_ = now_time;
368 playout_diff_times_[diff_time]++;
369
henrika3f33e2a2016-07-06 00:33:57 -0700370 // TOOD(henrika): improve bad locking model and make it more clear that only
371 // 10ms buffer sizes is supported in WebRTC.
henrika0fd68012016-07-04 13:01:19 +0200372 {
henrika6c4d0f02016-07-14 05:54:19 -0700373 rtc::CritScope lock(&_critSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000374
henrika0fd68012016-07-04 13:01:19 +0200375 // Store copies under lock and use copies hereafter to avoid race with
376 // setter methods.
377 playSampleRate = _playSampleRate;
378 playBytesPerSample = _playBytesPerSample;
379 playChannels = _playChannels;
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000380
henrika0fd68012016-07-04 13:01:19 +0200381 // Ensure that user has initialized all essential members
382 if ((playBytesPerSample == 0) || (playChannels == 0) ||
383 (playSampleRate == 0)) {
henrika3f33e2a2016-07-06 00:33:57 -0700384 RTC_NOTREACHED();
henrika0fd68012016-07-04 13:01:19 +0200385 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000386 }
387
henrika0fd68012016-07-04 13:01:19 +0200388 _playSamples = nSamples;
389 _playSize = playBytesPerSample * nSamples; // {2,4}*nSamples
henrika3f33e2a2016-07-06 00:33:57 -0700390 RTC_CHECK_LE(_playSize, kMaxBufferSizeBytes);
391 RTC_CHECK_EQ(nSamples, _playSamples);
henrika0fd68012016-07-04 13:01:19 +0200392 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000393
henrika0fd68012016-07-04 13:01:19 +0200394 size_t nSamplesOut(0);
395
henrika6c4d0f02016-07-14 05:54:19 -0700396 rtc::CritScope lock(&_critSectCb);
henrika0fd68012016-07-04 13:01:19 +0200397
henrika3f33e2a2016-07-06 00:33:57 -0700398 // It is currently supported to start playout without a valid audio
399 // transport object. Leads to warning and silence.
400 if (!_ptrCbAudioTransport) {
401 LOG(LS_WARNING) << "Invalid audio transport";
henrika0fd68012016-07-04 13:01:19 +0200402 return 0;
403 }
404
henrika3f33e2a2016-07-06 00:33:57 -0700405 uint32_t res(0);
406 int64_t elapsed_time_ms = -1;
407 int64_t ntp_time_ms = -1;
408 res = _ptrCbAudioTransport->NeedMorePlayData(
409 _playSamples, playBytesPerSample, playChannels, playSampleRate,
410 &_playBuffer[0], nSamplesOut, &elapsed_time_ms, &ntp_time_ms);
411 if (res != 0) {
412 LOG(LS_ERROR) << "NeedMorePlayData() failed";
henrika0fd68012016-07-04 13:01:19 +0200413 }
414
henrika6c4d0f02016-07-14 05:54:19 -0700415 // Update some stats but do it on the task queue to ensure that access of
416 // members is serialized hence avoiding usage of locks.
417 task_queue_.PostTask(
418 rtc::Bind(&AudioDeviceBuffer::UpdatePlayStats, this, nSamplesOut));
419
henrika0fd68012016-07-04 13:01:19 +0200420 return static_cast<int32_t>(nSamplesOut);
niklase@google.com470e71d2011-07-07 08:21:25 +0000421}
422
henrika0fd68012016-07-04 13:01:19 +0200423int32_t AudioDeviceBuffer::GetPlayoutData(void* audioBuffer) {
henrika6c4d0f02016-07-14 05:54:19 -0700424 rtc::CritScope lock(&_critSect);
henrika3f33e2a2016-07-06 00:33:57 -0700425 RTC_CHECK_LE(_playSize, kMaxBufferSizeBytes);
punyabrata@webrtc.orgc9801462011-11-29 18:49:54 +0000426
henrika0fd68012016-07-04 13:01:19 +0200427 memcpy(audioBuffer, &_playBuffer[0], _playSize);
niklase@google.com470e71d2011-07-07 08:21:25 +0000428
henrika0fd68012016-07-04 13:01:19 +0200429 if (_playFile.is_open()) {
430 // write to binary file in mono or stereo (interleaved)
431 _playFile.Write(&_playBuffer[0], _playSize);
432 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000433
henrika0fd68012016-07-04 13:01:19 +0200434 return static_cast<int32_t>(_playSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +0000435}
436
henrika6c4d0f02016-07-14 05:54:19 -0700437void AudioDeviceBuffer::StartTimer() {
438 last_log_stat_time_ = rtc::TimeMillis();
439 task_queue_.PostDelayedTask(rtc::Bind(&AudioDeviceBuffer::LogStats, this),
440 kTimerIntervalInMilliseconds);
441}
442
443void AudioDeviceBuffer::LogStats() {
444 RTC_DCHECK(task_queue_.IsCurrent());
445
446 int64_t now_time = rtc::TimeMillis();
447 int64_t next_callback_time = now_time + kTimerIntervalInMilliseconds;
448 int64_t time_since_last = rtc::TimeDiff(now_time, last_log_stat_time_);
449 last_log_stat_time_ = now_time;
450
451 // 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
453 // after ~20 seconds.
454 if (++num_stat_reports_ > 1) {
455 uint32_t diff_samples = rec_samples_ - last_rec_samples_;
456 uint32_t rate = diff_samples / kTimerIntervalInSeconds;
457 LOG(INFO) << "[REC : " << time_since_last << "msec, "
458 << _recSampleRate / 1000
459 << "kHz] callbacks: " << rec_callbacks_ - last_rec_callbacks_
460 << ", "
461 << "samples: " << diff_samples << ", "
462 << "rate: " << rate;
463
464 diff_samples = play_samples_ - last_play_samples_;
465 rate = diff_samples / kTimerIntervalInSeconds;
466 LOG(INFO) << "[PLAY: " << time_since_last << "msec, "
467 << _playSampleRate / 1000
468 << "kHz] callbacks: " << play_callbacks_ - last_play_callbacks_
469 << ", "
470 << "samples: " << diff_samples << ", "
471 << "rate: " << rate;
472 }
473
474 last_rec_callbacks_ = rec_callbacks_;
475 last_play_callbacks_ = play_callbacks_;
476 last_rec_samples_ = rec_samples_;
477 last_play_samples_ = play_samples_;
478
479 int64_t time_to_wait_ms = next_callback_time - rtc::TimeMillis();
480 RTC_DCHECK_GT(time_to_wait_ms, 0) << "Invalid timer interval";
481
482 // Update some stats but do it on the task queue to ensure that access of
483 // members is serialized hence avoiding usage of locks.
484 task_queue_.PostDelayedTask(rtc::Bind(&AudioDeviceBuffer::LogStats, this),
485 time_to_wait_ms);
486}
487
488void AudioDeviceBuffer::UpdateRecStats(size_t num_samples) {
489 RTC_DCHECK(task_queue_.IsCurrent());
490 ++rec_callbacks_;
491 rec_samples_ += num_samples;
492}
493
494void AudioDeviceBuffer::UpdatePlayStats(size_t num_samples) {
495 RTC_DCHECK(task_queue_.IsCurrent());
496 ++play_callbacks_;
497 play_samples_ += num_samples;
498}
499
niklase@google.com470e71d2011-07-07 08:21:25 +0000500} // namespace webrtc