1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
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
11 #include "webrtc/modules/audio_device/audio_device_buffer.h"
12
13 #include <assert.h>
14 #include <string.h>
15
16 #include "webrtc/base/format_macros.h"
17 #include "webrtc/modules/audio_device/audio_device_config.h"
18 #include "webrtc/system_wrappers/include/critical_section_wrapper.h"
19 #include "webrtc/system_wrappers/include/logging.h"
20 #include "webrtc/system_wrappers/include/trace.h"
21
22 namespace webrtc {
23
24 static const int kHighDelayThresholdMs = 300;
25 static const int kLogHighDelayIntervalFrames = 500; // 5 seconds.
26
27 // ----------------------------------------------------------------------------
28 // ctor
29 // ----------------------------------------------------------------------------
30
AudioDeviceBuffer()31 AudioDeviceBuffer::AudioDeviceBuffer() :
32 _id(-1),
33 _critSect(*CriticalSectionWrapper::CreateCriticalSection()),
34 _critSectCb(*CriticalSectionWrapper::CreateCriticalSection()),
35 _ptrCbAudioTransport(NULL),
36 _recSampleRate(0),
37 _playSampleRate(0),
38 _recChannels(0),
39 _playChannels(0),
40 _recChannel(AudioDeviceModule::kChannelBoth),
41 _recBytesPerSample(0),
42 _playBytesPerSample(0),
43 _recSamples(0),
44 _recSize(0),
45 _playSamples(0),
46 _playSize(0),
47 _recFile(*FileWrapper::Create()),
48 _playFile(*FileWrapper::Create()),
49 _currentMicLevel(0),
50 _newMicLevel(0),
51 _typingStatus(false),
52 _playDelayMS(0),
53 _recDelayMS(0),
54 _clockDrift(0),
55 // Set to the interval in order to log on the first occurrence.
56 high_delay_counter_(kLogHighDelayIntervalFrames) {
57 // valid ID will be set later by SetId, use -1 for now
58 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s created", __FUNCTION__);
59 memset(_recBuffer, 0, kMaxBufferSizeBytes);
60 memset(_playBuffer, 0, kMaxBufferSizeBytes);
61 }
62
63 // ----------------------------------------------------------------------------
64 // dtor
65 // ----------------------------------------------------------------------------
66
~AudioDeviceBuffer()67 AudioDeviceBuffer::~AudioDeviceBuffer()
68 {
69 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s destroyed", __FUNCTION__);
70 {
71 CriticalSectionScoped lock(&_critSect);
72
73 _recFile.Flush();
74 _recFile.CloseFile();
75 delete &_recFile;
76
77 _playFile.Flush();
78 _playFile.CloseFile();
79 delete &_playFile;
80 }
81
82 delete &_critSect;
83 delete &_critSectCb;
84 }
85
86 // ----------------------------------------------------------------------------
87 // SetId
88 // ----------------------------------------------------------------------------
89
SetId(uint32_t id)90 void AudioDeviceBuffer::SetId(uint32_t id)
91 {
92 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, id, "AudioDeviceBuffer::SetId(id=%d)", id);
93 _id = id;
94 }
95
96 // ----------------------------------------------------------------------------
97 // RegisterAudioCallback
98 // ----------------------------------------------------------------------------
99
RegisterAudioCallback(AudioTransport * audioCallback)100 int32_t AudioDeviceBuffer::RegisterAudioCallback(AudioTransport* audioCallback)
101 {
102 CriticalSectionScoped lock(&_critSectCb);
103 _ptrCbAudioTransport = audioCallback;
104
105 return 0;
106 }
107
108 // ----------------------------------------------------------------------------
109 // InitPlayout
110 // ----------------------------------------------------------------------------
111
InitPlayout()112 int32_t AudioDeviceBuffer::InitPlayout()
113 {
114 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
115 return 0;
116 }
117
118 // ----------------------------------------------------------------------------
119 // InitRecording
120 // ----------------------------------------------------------------------------
121
InitRecording()122 int32_t AudioDeviceBuffer::InitRecording()
123 {
124 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
125 return 0;
126 }
127
128 // ----------------------------------------------------------------------------
129 // SetRecordingSampleRate
130 // ----------------------------------------------------------------------------
131
SetRecordingSampleRate(uint32_t fsHz)132 int32_t AudioDeviceBuffer::SetRecordingSampleRate(uint32_t fsHz)
133 {
134 CriticalSectionScoped lock(&_critSect);
135 _recSampleRate = fsHz;
136 return 0;
137 }
138
139 // ----------------------------------------------------------------------------
140 // SetPlayoutSampleRate
141 // ----------------------------------------------------------------------------
142
SetPlayoutSampleRate(uint32_t fsHz)143 int32_t AudioDeviceBuffer::SetPlayoutSampleRate(uint32_t fsHz)
144 {
145 CriticalSectionScoped lock(&_critSect);
146 _playSampleRate = fsHz;
147 return 0;
148 }
149
150 // ----------------------------------------------------------------------------
151 // RecordingSampleRate
152 // ----------------------------------------------------------------------------
153
RecordingSampleRate() const154 int32_t AudioDeviceBuffer::RecordingSampleRate() const
155 {
156 return _recSampleRate;
157 }
158
159 // ----------------------------------------------------------------------------
160 // PlayoutSampleRate
161 // ----------------------------------------------------------------------------
162
PlayoutSampleRate() const163 int32_t AudioDeviceBuffer::PlayoutSampleRate() const
164 {
165 return _playSampleRate;
166 }
167
168 // ----------------------------------------------------------------------------
169 // SetRecordingChannels
170 // ----------------------------------------------------------------------------
171
SetRecordingChannels(size_t channels)172 int32_t AudioDeviceBuffer::SetRecordingChannels(size_t channels)
173 {
174 CriticalSectionScoped lock(&_critSect);
175 _recChannels = channels;
176 _recBytesPerSample = 2*channels; // 16 bits per sample in mono, 32 bits in stereo
177 return 0;
178 }
179
180 // ----------------------------------------------------------------------------
181 // SetPlayoutChannels
182 // ----------------------------------------------------------------------------
183
SetPlayoutChannels(size_t channels)184 int32_t AudioDeviceBuffer::SetPlayoutChannels(size_t channels)
185 {
186 CriticalSectionScoped lock(&_critSect);
187 _playChannels = channels;
188 // 16 bits per sample in mono, 32 bits in stereo
189 _playBytesPerSample = 2*channels;
190 return 0;
191 }
192
193 // ----------------------------------------------------------------------------
194 // SetRecordingChannel
195 //
196 // Select which channel to use while recording.
197 // This API requires that stereo is enabled.
198 //
199 // Note that, the nChannel parameter in RecordedDataIsAvailable will be
200 // set to 2 even for kChannelLeft and kChannelRight. However, nBytesPerSample
201 // will be 2 instead of 4 four these cases.
202 // ----------------------------------------------------------------------------
203
SetRecordingChannel(const AudioDeviceModule::ChannelType channel)204 int32_t AudioDeviceBuffer::SetRecordingChannel(const AudioDeviceModule::ChannelType channel)
205 {
206 CriticalSectionScoped lock(&_critSect);
207
208 if (_recChannels == 1)
209 {
210 return -1;
211 }
212
213 if (channel == AudioDeviceModule::kChannelBoth)
214 {
215 // two bytes per channel
216 _recBytesPerSample = 4;
217 }
218 else
219 {
220 // only utilize one out of two possible channels (left or right)
221 _recBytesPerSample = 2;
222 }
223 _recChannel = channel;
224
225 return 0;
226 }
227
228 // ----------------------------------------------------------------------------
229 // RecordingChannel
230 // ----------------------------------------------------------------------------
231
RecordingChannel(AudioDeviceModule::ChannelType & channel) const232 int32_t AudioDeviceBuffer::RecordingChannel(AudioDeviceModule::ChannelType& channel) const
233 {
234 channel = _recChannel;
235 return 0;
236 }
237
238 // ----------------------------------------------------------------------------
239 // RecordingChannels
240 // ----------------------------------------------------------------------------
241
RecordingChannels() const242 size_t AudioDeviceBuffer::RecordingChannels() const
243 {
244 return _recChannels;
245 }
246
247 // ----------------------------------------------------------------------------
248 // PlayoutChannels
249 // ----------------------------------------------------------------------------
250
PlayoutChannels() const251 size_t AudioDeviceBuffer::PlayoutChannels() const
252 {
253 return _playChannels;
254 }
255
256 // ----------------------------------------------------------------------------
257 // SetCurrentMicLevel
258 // ----------------------------------------------------------------------------
259
SetCurrentMicLevel(uint32_t level)260 int32_t AudioDeviceBuffer::SetCurrentMicLevel(uint32_t level)
261 {
262 _currentMicLevel = level;
263 return 0;
264 }
265
SetTypingStatus(bool typingStatus)266 int32_t AudioDeviceBuffer::SetTypingStatus(bool typingStatus)
267 {
268 _typingStatus = typingStatus;
269 return 0;
270 }
271
272 // ----------------------------------------------------------------------------
273 // NewMicLevel
274 // ----------------------------------------------------------------------------
275
NewMicLevel() const276 uint32_t AudioDeviceBuffer::NewMicLevel() const
277 {
278 return _newMicLevel;
279 }
280
281 // ----------------------------------------------------------------------------
282 // SetVQEData
283 // ----------------------------------------------------------------------------
284
SetVQEData(int playDelayMs,int recDelayMs,int clockDrift)285 void AudioDeviceBuffer::SetVQEData(int playDelayMs, int recDelayMs,
286 int clockDrift) {
287 if (high_delay_counter_ < kLogHighDelayIntervalFrames) {
288 ++high_delay_counter_;
289 } else {
290 if (playDelayMs + recDelayMs > kHighDelayThresholdMs) {
291 high_delay_counter_ = 0;
292 LOG(LS_WARNING) << "High audio device delay reported (render="
293 << playDelayMs << " ms, capture=" << recDelayMs << " ms)";
294 }
295 }
296
297 _playDelayMS = playDelayMs;
298 _recDelayMS = recDelayMs;
299 _clockDrift = clockDrift;
300 }
301
302 // ----------------------------------------------------------------------------
303 // StartInputFileRecording
304 // ----------------------------------------------------------------------------
305
StartInputFileRecording(const char fileName[kAdmMaxFileNameSize])306 int32_t AudioDeviceBuffer::StartInputFileRecording(
307 const char fileName[kAdmMaxFileNameSize])
308 {
309 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
310
311 CriticalSectionScoped lock(&_critSect);
312
313 _recFile.Flush();
314 _recFile.CloseFile();
315
316 return (_recFile.OpenFile(fileName, false, false, false));
317 }
318
319 // ----------------------------------------------------------------------------
320 // StopInputFileRecording
321 // ----------------------------------------------------------------------------
322
StopInputFileRecording()323 int32_t AudioDeviceBuffer::StopInputFileRecording()
324 {
325 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
326
327 CriticalSectionScoped lock(&_critSect);
328
329 _recFile.Flush();
330 _recFile.CloseFile();
331
332 return 0;
333 }
334
335 // ----------------------------------------------------------------------------
336 // StartOutputFileRecording
337 // ----------------------------------------------------------------------------
338
StartOutputFileRecording(const char fileName[kAdmMaxFileNameSize])339 int32_t AudioDeviceBuffer::StartOutputFileRecording(
340 const char fileName[kAdmMaxFileNameSize])
341 {
342 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
343
344 CriticalSectionScoped lock(&_critSect);
345
346 _playFile.Flush();
347 _playFile.CloseFile();
348
349 return (_playFile.OpenFile(fileName, false, false, false));
350 }
351
352 // ----------------------------------------------------------------------------
353 // StopOutputFileRecording
354 // ----------------------------------------------------------------------------
355
StopOutputFileRecording()356 int32_t AudioDeviceBuffer::StopOutputFileRecording()
357 {
358 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
359
360 CriticalSectionScoped lock(&_critSect);
361
362 _playFile.Flush();
363 _playFile.CloseFile();
364
365 return 0;
366 }
367
368 // ----------------------------------------------------------------------------
369 // SetRecordedBuffer
370 //
371 // Store recorded audio buffer in local memory ready for the actual
372 // "delivery" using a callback.
373 //
374 // This method can also parse out left or right channel from a stereo
375 // input signal, i.e., emulate mono.
376 //
377 // Examples:
378 //
379 // 16-bit,48kHz mono, 10ms => nSamples=480 => _recSize=2*480=960 bytes
380 // 16-bit,48kHz stereo,10ms => nSamples=480 => _recSize=4*480=1920 bytes
381 // ----------------------------------------------------------------------------
382
SetRecordedBuffer(const void * audioBuffer,size_t nSamples)383 int32_t AudioDeviceBuffer::SetRecordedBuffer(const void* audioBuffer,
384 size_t nSamples)
385 {
386 CriticalSectionScoped lock(&_critSect);
387
388 if (_recBytesPerSample == 0)
389 {
390 assert(false);
391 return -1;
392 }
393
394 _recSamples = nSamples;
395 _recSize = _recBytesPerSample*nSamples; // {2,4}*nSamples
396 if (_recSize > kMaxBufferSizeBytes)
397 {
398 assert(false);
399 return -1;
400 }
401
402 if (_recChannel == AudioDeviceModule::kChannelBoth)
403 {
404 // (default) copy the complete input buffer to the local buffer
405 memcpy(&_recBuffer[0], audioBuffer, _recSize);
406 }
407 else
408 {
409 int16_t* ptr16In = (int16_t*)audioBuffer;
410 int16_t* ptr16Out = (int16_t*)&_recBuffer[0];
411
412 if (AudioDeviceModule::kChannelRight == _recChannel)
413 {
414 ptr16In++;
415 }
416
417 // exctract left or right channel from input buffer to the local buffer
418 for (size_t i = 0; i < _recSamples; i++)
419 {
420 *ptr16Out = *ptr16In;
421 ptr16Out++;
422 ptr16In++;
423 ptr16In++;
424 }
425 }
426
427 if (_recFile.Open())
428 {
429 // write to binary file in mono or stereo (interleaved)
430 _recFile.Write(&_recBuffer[0], _recSize);
431 }
432
433 return 0;
434 }
435
436 // ----------------------------------------------------------------------------
437 // DeliverRecordedData
438 // ----------------------------------------------------------------------------
439
DeliverRecordedData()440 int32_t AudioDeviceBuffer::DeliverRecordedData()
441 {
442 CriticalSectionScoped lock(&_critSectCb);
443
444 // Ensure that user has initialized all essential members
445 if ((_recSampleRate == 0) ||
446 (_recSamples == 0) ||
447 (_recBytesPerSample == 0) ||
448 (_recChannels == 0))
449 {
450 assert(false);
451 return -1;
452 }
453
454 if (_ptrCbAudioTransport == NULL)
455 {
456 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "failed to deliver recorded data (AudioTransport does not exist)");
457 return 0;
458 }
459
460 int32_t res(0);
461 uint32_t newMicLevel(0);
462 uint32_t totalDelayMS = _playDelayMS +_recDelayMS;
463
464 res = _ptrCbAudioTransport->RecordedDataIsAvailable(&_recBuffer[0],
465 _recSamples,
466 _recBytesPerSample,
467 _recChannels,
468 _recSampleRate,
469 totalDelayMS,
470 _clockDrift,
471 _currentMicLevel,
472 _typingStatus,
473 newMicLevel);
474 if (res != -1)
475 {
476 _newMicLevel = newMicLevel;
477 }
478
479 return 0;
480 }
481
482 // ----------------------------------------------------------------------------
483 // RequestPlayoutData
484 // ----------------------------------------------------------------------------
485
RequestPlayoutData(size_t nSamples)486 int32_t AudioDeviceBuffer::RequestPlayoutData(size_t nSamples)
487 {
488 uint32_t playSampleRate = 0;
489 size_t playBytesPerSample = 0;
490 size_t playChannels = 0;
491 {
492 CriticalSectionScoped lock(&_critSect);
493
494 // Store copies under lock and use copies hereafter to avoid race with
495 // setter methods.
496 playSampleRate = _playSampleRate;
497 playBytesPerSample = _playBytesPerSample;
498 playChannels = _playChannels;
499
500 // Ensure that user has initialized all essential members
501 if ((playBytesPerSample == 0) ||
502 (playChannels == 0) ||
503 (playSampleRate == 0))
504 {
505 assert(false);
506 return -1;
507 }
508
509 _playSamples = nSamples;
510 _playSize = playBytesPerSample * nSamples; // {2,4}*nSamples
511 if (_playSize > kMaxBufferSizeBytes)
512 {
513 assert(false);
514 return -1;
515 }
516
517 if (nSamples != _playSamples)
518 {
519 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "invalid number of samples to be played out (%d)", nSamples);
520 return -1;
521 }
522 }
523
524 size_t nSamplesOut(0);
525
526 CriticalSectionScoped lock(&_critSectCb);
527
528 if (_ptrCbAudioTransport == NULL)
529 {
530 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "failed to feed data to playout (AudioTransport does not exist)");
531 return 0;
532 }
533
534 if (_ptrCbAudioTransport)
535 {
536 uint32_t res(0);
537 int64_t elapsed_time_ms = -1;
538 int64_t ntp_time_ms = -1;
539 res = _ptrCbAudioTransport->NeedMorePlayData(_playSamples,
540 playBytesPerSample,
541 playChannels,
542 playSampleRate,
543 &_playBuffer[0],
544 nSamplesOut,
545 &elapsed_time_ms,
546 &ntp_time_ms);
547 if (res != 0)
548 {
549 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "NeedMorePlayData() failed");
550 }
551 }
552
553 return static_cast<int32_t>(nSamplesOut);
554 }
555
556 // ----------------------------------------------------------------------------
557 // GetPlayoutData
558 // ----------------------------------------------------------------------------
559
GetPlayoutData(void * audioBuffer)560 int32_t AudioDeviceBuffer::GetPlayoutData(void* audioBuffer)
561 {
562 CriticalSectionScoped lock(&_critSect);
563
564 if (_playSize > kMaxBufferSizeBytes)
565 {
566 WEBRTC_TRACE(kTraceError, kTraceUtility, _id,
567 "_playSize %" PRIuS " exceeds kMaxBufferSizeBytes in "
568 "AudioDeviceBuffer::GetPlayoutData", _playSize);
569 assert(false);
570 return -1;
571 }
572
573 memcpy(audioBuffer, &_playBuffer[0], _playSize);
574
575 if (_playFile.Open())
576 {
577 // write to binary file in mono or stereo (interleaved)
578 _playFile.Write(&_playBuffer[0], _playSize);
579 }
580
581 return static_cast<int32_t>(_playSamples);
582 }
583
584 } // namespace webrtc
585