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 22namespace webrtc { 23 24static const int kHighDelayThresholdMs = 300; 25static const int kLogHighDelayIntervalFrames = 500; // 5 seconds. 26 27// ---------------------------------------------------------------------------- 28// ctor 29// ---------------------------------------------------------------------------- 30 31AudioDeviceBuffer::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 67AudioDeviceBuffer::~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 90void 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 100int32_t AudioDeviceBuffer::RegisterAudioCallback(AudioTransport* audioCallback) 101{ 102 CriticalSectionScoped lock(&_critSectCb); 103 _ptrCbAudioTransport = audioCallback; 104 105 return 0; 106} 107 108// ---------------------------------------------------------------------------- 109// InitPlayout 110// ---------------------------------------------------------------------------- 111 112int32_t AudioDeviceBuffer::InitPlayout() 113{ 114 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__); 115 return 0; 116} 117 118// ---------------------------------------------------------------------------- 119// InitRecording 120// ---------------------------------------------------------------------------- 121 122int32_t AudioDeviceBuffer::InitRecording() 123{ 124 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__); 125 return 0; 126} 127 128// ---------------------------------------------------------------------------- 129// SetRecordingSampleRate 130// ---------------------------------------------------------------------------- 131 132int32_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 145int32_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 158int32_t AudioDeviceBuffer::RecordingSampleRate() const 159{ 160 return _recSampleRate; 161} 162 163// ---------------------------------------------------------------------------- 164// PlayoutSampleRate 165// ---------------------------------------------------------------------------- 166 167int32_t AudioDeviceBuffer::PlayoutSampleRate() const 168{ 169 return _playSampleRate; 170} 171 172// ---------------------------------------------------------------------------- 173// SetRecordingChannels 174// ---------------------------------------------------------------------------- 175 176int32_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 190int32_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 212int32_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 240int32_t AudioDeviceBuffer::RecordingChannel(AudioDeviceModule::ChannelType& channel) const 241{ 242 channel = _recChannel; 243 return 0; 244} 245 246// ---------------------------------------------------------------------------- 247// RecordingChannels 248// ---------------------------------------------------------------------------- 249 250uint8_t AudioDeviceBuffer::RecordingChannels() const 251{ 252 return _recChannels; 253} 254 255// ---------------------------------------------------------------------------- 256// PlayoutChannels 257// ---------------------------------------------------------------------------- 258 259uint8_t AudioDeviceBuffer::PlayoutChannels() const 260{ 261 return _playChannels; 262} 263 264// ---------------------------------------------------------------------------- 265// SetCurrentMicLevel 266// ---------------------------------------------------------------------------- 267 268int32_t AudioDeviceBuffer::SetCurrentMicLevel(uint32_t level) 269{ 270 _currentMicLevel = level; 271 return 0; 272} 273 274int32_t AudioDeviceBuffer::SetTypingStatus(bool typingStatus) 275{ 276 _typingStatus = typingStatus; 277 return 0; 278} 279 280// ---------------------------------------------------------------------------- 281// NewMicLevel 282// ---------------------------------------------------------------------------- 283 284uint32_t AudioDeviceBuffer::NewMicLevel() const 285{ 286 return _newMicLevel; 287} 288 289// ---------------------------------------------------------------------------- 290// SetVQEData 291// ---------------------------------------------------------------------------- 292 293void 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 314int32_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 331int32_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 347int32_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 364int32_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 391int32_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 454int32_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 500int32_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 574int32_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