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/modules/audio_device/audio_device_config.h"
17 #include "webrtc/modules/audio_device/audio_device_utility.h"
18 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
19 #include "webrtc/system_wrappers/interface/logging.h"
20 #include "webrtc/system_wrappers/interface/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 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "AudioDeviceBuffer::SetRecordingSampleRate(fsHz=%u)", fsHz);
135
136 CriticalSectionScoped lock(&_critSect);
137 _recSampleRate = fsHz;
138 return 0;
139 }
140
141 // ----------------------------------------------------------------------------
142 // SetPlayoutSampleRate
143 // ----------------------------------------------------------------------------
144
SetPlayoutSampleRate(uint32_t fsHz)145 int32_t AudioDeviceBuffer::SetPlayoutSampleRate(uint32_t fsHz)
146 {
147 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "AudioDeviceBuffer::SetPlayoutSampleRate(fsHz=%u)", fsHz);
148
149 CriticalSectionScoped lock(&_critSect);
150 _playSampleRate = fsHz;
151 return 0;
152 }
153
154 // ----------------------------------------------------------------------------
155 // RecordingSampleRate
156 // ----------------------------------------------------------------------------
157
RecordingSampleRate() const158 int32_t AudioDeviceBuffer::RecordingSampleRate() const
159 {
160 return _recSampleRate;
161 }
162
163 // ----------------------------------------------------------------------------
164 // PlayoutSampleRate
165 // ----------------------------------------------------------------------------
166
PlayoutSampleRate() const167 int32_t AudioDeviceBuffer::PlayoutSampleRate() const
168 {
169 return _playSampleRate;
170 }
171
172 // ----------------------------------------------------------------------------
173 // SetRecordingChannels
174 // ----------------------------------------------------------------------------
175
SetRecordingChannels(uint8_t channels)176 int32_t AudioDeviceBuffer::SetRecordingChannels(uint8_t channels)
177 {
178 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "AudioDeviceBuffer::SetRecordingChannels(channels=%u)", channels);
179
180 CriticalSectionScoped lock(&_critSect);
181 _recChannels = channels;
182 _recBytesPerSample = 2*channels; // 16 bits per sample in mono, 32 bits in stereo
183 return 0;
184 }
185
186 // ----------------------------------------------------------------------------
187 // SetPlayoutChannels
188 // ----------------------------------------------------------------------------
189
SetPlayoutChannels(uint8_t channels)190 int32_t AudioDeviceBuffer::SetPlayoutChannels(uint8_t channels)
191 {
192 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "AudioDeviceBuffer::SetPlayoutChannels(channels=%u)", channels);
193
194 CriticalSectionScoped lock(&_critSect);
195 _playChannels = channels;
196 // 16 bits per sample in mono, 32 bits in stereo
197 _playBytesPerSample = 2*channels;
198 return 0;
199 }
200
201 // ----------------------------------------------------------------------------
202 // SetRecordingChannel
203 //
204 // Select which channel to use while recording.
205 // This API requires that stereo is enabled.
206 //
207 // Note that, the nChannel parameter in RecordedDataIsAvailable will be
208 // set to 2 even for kChannelLeft and kChannelRight. However, nBytesPerSample
209 // will be 2 instead of 4 four these cases.
210 // ----------------------------------------------------------------------------
211
SetRecordingChannel(const AudioDeviceModule::ChannelType channel)212 int32_t AudioDeviceBuffer::SetRecordingChannel(const AudioDeviceModule::ChannelType channel)
213 {
214 CriticalSectionScoped lock(&_critSect);
215
216 if (_recChannels == 1)
217 {
218 return -1;
219 }
220
221 if (channel == AudioDeviceModule::kChannelBoth)
222 {
223 // two bytes per channel
224 _recBytesPerSample = 4;
225 }
226 else
227 {
228 // only utilize one out of two possible channels (left or right)
229 _recBytesPerSample = 2;
230 }
231 _recChannel = channel;
232
233 return 0;
234 }
235
236 // ----------------------------------------------------------------------------
237 // RecordingChannel
238 // ----------------------------------------------------------------------------
239
RecordingChannel(AudioDeviceModule::ChannelType & channel) const240 int32_t AudioDeviceBuffer::RecordingChannel(AudioDeviceModule::ChannelType& channel) const
241 {
242 channel = _recChannel;
243 return 0;
244 }
245
246 // ----------------------------------------------------------------------------
247 // RecordingChannels
248 // ----------------------------------------------------------------------------
249
RecordingChannels() const250 uint8_t AudioDeviceBuffer::RecordingChannels() const
251 {
252 return _recChannels;
253 }
254
255 // ----------------------------------------------------------------------------
256 // PlayoutChannels
257 // ----------------------------------------------------------------------------
258
PlayoutChannels() const259 uint8_t AudioDeviceBuffer::PlayoutChannels() const
260 {
261 return _playChannels;
262 }
263
264 // ----------------------------------------------------------------------------
265 // SetCurrentMicLevel
266 // ----------------------------------------------------------------------------
267
SetCurrentMicLevel(uint32_t level)268 int32_t AudioDeviceBuffer::SetCurrentMicLevel(uint32_t level)
269 {
270 _currentMicLevel = level;
271 return 0;
272 }
273
SetTypingStatus(bool typingStatus)274 int32_t AudioDeviceBuffer::SetTypingStatus(bool typingStatus)
275 {
276 _typingStatus = typingStatus;
277 return 0;
278 }
279
280 // ----------------------------------------------------------------------------
281 // NewMicLevel
282 // ----------------------------------------------------------------------------
283
NewMicLevel() const284 uint32_t AudioDeviceBuffer::NewMicLevel() const
285 {
286 return _newMicLevel;
287 }
288
289 // ----------------------------------------------------------------------------
290 // SetVQEData
291 // ----------------------------------------------------------------------------
292
SetVQEData(int playDelayMs,int recDelayMs,int clockDrift)293 void AudioDeviceBuffer::SetVQEData(int playDelayMs, int recDelayMs,
294 int clockDrift) {
295 if (high_delay_counter_ < kLogHighDelayIntervalFrames) {
296 ++high_delay_counter_;
297 } else {
298 if (playDelayMs + recDelayMs > kHighDelayThresholdMs) {
299 high_delay_counter_ = 0;
300 LOG(LS_WARNING) << "High audio device delay reported (render="
301 << playDelayMs << " ms, capture=" << recDelayMs << " ms)";
302 }
303 }
304
305 _playDelayMS = playDelayMs;
306 _recDelayMS = recDelayMs;
307 _clockDrift = clockDrift;
308 }
309
310 // ----------------------------------------------------------------------------
311 // StartInputFileRecording
312 // ----------------------------------------------------------------------------
313
StartInputFileRecording(const char fileName[kAdmMaxFileNameSize])314 int32_t AudioDeviceBuffer::StartInputFileRecording(
315 const char fileName[kAdmMaxFileNameSize])
316 {
317 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
318
319 CriticalSectionScoped lock(&_critSect);
320
321 _recFile.Flush();
322 _recFile.CloseFile();
323
324 return (_recFile.OpenFile(fileName, false, false, false));
325 }
326
327 // ----------------------------------------------------------------------------
328 // StopInputFileRecording
329 // ----------------------------------------------------------------------------
330
StopInputFileRecording()331 int32_t AudioDeviceBuffer::StopInputFileRecording()
332 {
333 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
334
335 CriticalSectionScoped lock(&_critSect);
336
337 _recFile.Flush();
338 _recFile.CloseFile();
339
340 return 0;
341 }
342
343 // ----------------------------------------------------------------------------
344 // StartOutputFileRecording
345 // ----------------------------------------------------------------------------
346
StartOutputFileRecording(const char fileName[kAdmMaxFileNameSize])347 int32_t AudioDeviceBuffer::StartOutputFileRecording(
348 const char fileName[kAdmMaxFileNameSize])
349 {
350 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
351
352 CriticalSectionScoped lock(&_critSect);
353
354 _playFile.Flush();
355 _playFile.CloseFile();
356
357 return (_playFile.OpenFile(fileName, false, false, false));
358 }
359
360 // ----------------------------------------------------------------------------
361 // StopOutputFileRecording
362 // ----------------------------------------------------------------------------
363
StopOutputFileRecording()364 int32_t AudioDeviceBuffer::StopOutputFileRecording()
365 {
366 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
367
368 CriticalSectionScoped lock(&_critSect);
369
370 _playFile.Flush();
371 _playFile.CloseFile();
372
373 return 0;
374 }
375
376 // ----------------------------------------------------------------------------
377 // SetRecordedBuffer
378 //
379 // Store recorded audio buffer in local memory ready for the actual
380 // "delivery" using a callback.
381 //
382 // This method can also parse out left or right channel from a stereo
383 // input signal, i.e., emulate mono.
384 //
385 // Examples:
386 //
387 // 16-bit,48kHz mono, 10ms => nSamples=480 => _recSize=2*480=960 bytes
388 // 16-bit,48kHz stereo,10ms => nSamples=480 => _recSize=4*480=1920 bytes
389 // ----------------------------------------------------------------------------
390
SetRecordedBuffer(const void * audioBuffer,uint32_t nSamples)391 int32_t AudioDeviceBuffer::SetRecordedBuffer(const void* audioBuffer,
392 uint32_t nSamples)
393 {
394 CriticalSectionScoped lock(&_critSect);
395
396 if (_recBytesPerSample == 0)
397 {
398 assert(false);
399 return -1;
400 }
401
402 _recSamples = nSamples;
403 _recSize = _recBytesPerSample*nSamples; // {2,4}*nSamples
404 if (_recSize > kMaxBufferSizeBytes)
405 {
406 assert(false);
407 return -1;
408 }
409
410 if (nSamples != _recSamples)
411 {
412 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "invalid number of recorded samples (%d)", nSamples);
413 return -1;
414 }
415
416 if (_recChannel == AudioDeviceModule::kChannelBoth)
417 {
418 // (default) copy the complete input buffer to the local buffer
419 memcpy(&_recBuffer[0], audioBuffer, _recSize);
420 }
421 else
422 {
423 int16_t* ptr16In = (int16_t*)audioBuffer;
424 int16_t* ptr16Out = (int16_t*)&_recBuffer[0];
425
426 if (AudioDeviceModule::kChannelRight == _recChannel)
427 {
428 ptr16In++;
429 }
430
431 // exctract left or right channel from input buffer to the local buffer
432 for (uint32_t i = 0; i < _recSamples; i++)
433 {
434 *ptr16Out = *ptr16In;
435 ptr16Out++;
436 ptr16In++;
437 ptr16In++;
438 }
439 }
440
441 if (_recFile.Open())
442 {
443 // write to binary file in mono or stereo (interleaved)
444 _recFile.Write(&_recBuffer[0], _recSize);
445 }
446
447 return 0;
448 }
449
450 // ----------------------------------------------------------------------------
451 // DeliverRecordedData
452 // ----------------------------------------------------------------------------
453
DeliverRecordedData()454 int32_t AudioDeviceBuffer::DeliverRecordedData()
455 {
456 CriticalSectionScoped lock(&_critSectCb);
457
458 // Ensure that user has initialized all essential members
459 if ((_recSampleRate == 0) ||
460 (_recSamples == 0) ||
461 (_recBytesPerSample == 0) ||
462 (_recChannels == 0))
463 {
464 assert(false);
465 return -1;
466 }
467
468 if (_ptrCbAudioTransport == NULL)
469 {
470 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "failed to deliver recorded data (AudioTransport does not exist)");
471 return 0;
472 }
473
474 int32_t res(0);
475 uint32_t newMicLevel(0);
476 uint32_t totalDelayMS = _playDelayMS +_recDelayMS;
477
478 res = _ptrCbAudioTransport->RecordedDataIsAvailable(&_recBuffer[0],
479 _recSamples,
480 _recBytesPerSample,
481 _recChannels,
482 _recSampleRate,
483 totalDelayMS,
484 _clockDrift,
485 _currentMicLevel,
486 _typingStatus,
487 newMicLevel);
488 if (res != -1)
489 {
490 _newMicLevel = newMicLevel;
491 }
492
493 return 0;
494 }
495
496 // ----------------------------------------------------------------------------
497 // RequestPlayoutData
498 // ----------------------------------------------------------------------------
499
RequestPlayoutData(uint32_t nSamples)500 int32_t AudioDeviceBuffer::RequestPlayoutData(uint32_t nSamples)
501 {
502 uint32_t playSampleRate = 0;
503 uint8_t playBytesPerSample = 0;
504 uint8_t playChannels = 0;
505 {
506 CriticalSectionScoped lock(&_critSect);
507
508 // Store copies under lock and use copies hereafter to avoid race with
509 // setter methods.
510 playSampleRate = _playSampleRate;
511 playBytesPerSample = _playBytesPerSample;
512 playChannels = _playChannels;
513
514 // Ensure that user has initialized all essential members
515 if ((playBytesPerSample == 0) ||
516 (playChannels == 0) ||
517 (playSampleRate == 0))
518 {
519 assert(false);
520 return -1;
521 }
522
523 _playSamples = nSamples;
524 _playSize = playBytesPerSample * nSamples; // {2,4}*nSamples
525 if (_playSize > kMaxBufferSizeBytes)
526 {
527 assert(false);
528 return -1;
529 }
530
531 if (nSamples != _playSamples)
532 {
533 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "invalid number of samples to be played out (%d)", nSamples);
534 return -1;
535 }
536 }
537
538 uint32_t nSamplesOut(0);
539
540 CriticalSectionScoped lock(&_critSectCb);
541
542 if (_ptrCbAudioTransport == NULL)
543 {
544 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "failed to feed data to playout (AudioTransport does not exist)");
545 return 0;
546 }
547
548 if (_ptrCbAudioTransport)
549 {
550 uint32_t res(0);
551 int64_t elapsed_time_ms = -1;
552 int64_t ntp_time_ms = -1;
553 res = _ptrCbAudioTransport->NeedMorePlayData(_playSamples,
554 playBytesPerSample,
555 playChannels,
556 playSampleRate,
557 &_playBuffer[0],
558 nSamplesOut,
559 &elapsed_time_ms,
560 &ntp_time_ms);
561 if (res != 0)
562 {
563 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "NeedMorePlayData() failed");
564 }
565 }
566
567 return nSamplesOut;
568 }
569
570 // ----------------------------------------------------------------------------
571 // GetPlayoutData
572 // ----------------------------------------------------------------------------
573
GetPlayoutData(void * audioBuffer)574 int32_t AudioDeviceBuffer::GetPlayoutData(void* audioBuffer)
575 {
576 CriticalSectionScoped lock(&_critSect);
577
578 if (_playSize > kMaxBufferSizeBytes)
579 {
580 WEBRTC_TRACE(kTraceError, kTraceUtility, _id, "_playSize %i exceeds "
581 "kMaxBufferSizeBytes in AudioDeviceBuffer::GetPlayoutData", _playSize);
582 assert(false);
583 return -1;
584 }
585
586 memcpy(audioBuffer, &_playBuffer[0], _playSize);
587
588 if (_playFile.Open())
589 {
590 // write to binary file in mono or stereo (interleaved)
591 _playFile.Write(&_playBuffer[0], _playSize);
592 }
593
594 return _playSamples;
595 }
596
597 } // namespace webrtc
598