| OLD | NEW |
| 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 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 60 "CallbackOnError(VE_TYPING_NOISE_OFF_WARNING)"); | 60 "CallbackOnError(VE_TYPING_NOISE_OFF_WARNING)"); |
| 61 _voiceEngineObserverPtr->CallbackOnError( | 61 _voiceEngineObserverPtr->CallbackOnError( |
| 62 -1, | 62 -1, |
| 63 VE_TYPING_NOISE_OFF_WARNING); | 63 VE_TYPING_NOISE_OFF_WARNING); |
| 64 } | 64 } |
| 65 } | 65 } |
| 66 } | 66 } |
| 67 } | 67 } |
| 68 #endif // WEBRTC_VOICE_ENGINE_TYPING_DETECTION | 68 #endif // WEBRTC_VOICE_ENGINE_TYPING_DETECTION |
| 69 | 69 |
| 70 void TransmitMixer::PlayNotification(int32_t id, | |
| 71 uint32_t durationMs) | |
| 72 { | |
| 73 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1), | |
| 74 "TransmitMixer::PlayNotification(id=%d, durationMs=%d)", | |
| 75 id, durationMs); | |
| 76 | |
| 77 // Not implement yet | |
| 78 } | |
| 79 | |
| 80 void TransmitMixer::RecordNotification(int32_t id, | |
| 81 uint32_t durationMs) | |
| 82 { | |
| 83 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1), | |
| 84 "TransmitMixer::RecordNotification(id=%d, durationMs=%d)", | |
| 85 id, durationMs); | |
| 86 | |
| 87 // Not implement yet | |
| 88 } | |
| 89 | |
| 90 void TransmitMixer::PlayFileEnded(int32_t id) | |
| 91 { | |
| 92 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1), | |
| 93 "TransmitMixer::PlayFileEnded(id=%d)", id); | |
| 94 | |
| 95 assert(id == _filePlayerId); | |
| 96 | |
| 97 rtc::CritScope cs(&_critSect); | |
| 98 | |
| 99 _filePlaying = false; | |
| 100 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1), | |
| 101 "TransmitMixer::PlayFileEnded() =>" | |
| 102 "file player module is shutdown"); | |
| 103 } | |
| 104 | |
| 105 void | |
| 106 TransmitMixer::RecordFileEnded(int32_t id) | |
| 107 { | |
| 108 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1), | |
| 109 "TransmitMixer::RecordFileEnded(id=%d)", id); | |
| 110 | |
| 111 if (id == _fileRecorderId) | |
| 112 { | |
| 113 rtc::CritScope cs(&_critSect); | |
| 114 _fileRecording = false; | |
| 115 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1), | |
| 116 "TransmitMixer::RecordFileEnded() => fileRecorder module" | |
| 117 "is shutdown"); | |
| 118 } else if (id == _fileCallRecorderId) | |
| 119 { | |
| 120 rtc::CritScope cs(&_critSect); | |
| 121 _fileCallRecording = false; | |
| 122 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1), | |
| 123 "TransmitMixer::RecordFileEnded() => fileCallRecorder" | |
| 124 "module is shutdown"); | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 int32_t | 70 int32_t |
| 129 TransmitMixer::Create(TransmitMixer*& mixer, uint32_t instanceId) | 71 TransmitMixer::Create(TransmitMixer*& mixer, uint32_t instanceId) |
| 130 { | 72 { |
| 131 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, -1), | 73 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, -1), |
| 132 "TransmitMixer::Create(instanceId=%d)", instanceId); | 74 "TransmitMixer::Create(instanceId=%d)", instanceId); |
| 133 mixer = new TransmitMixer(instanceId); | 75 mixer = new TransmitMixer(instanceId); |
| 134 if (mixer == NULL) | 76 if (mixer == NULL) |
| 135 { | 77 { |
| 136 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, -1), | 78 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, -1), |
| 137 "TransmitMixer::Create() unable to allocate memory" | 79 "TransmitMixer::Create() unable to allocate memory" |
| 138 "for mixer"); | 80 "for mixer"); |
| 139 return -1; | 81 return -1; |
| 140 } | 82 } |
| 141 return 0; | 83 return 0; |
| 142 } | 84 } |
| 143 | 85 |
| 144 void | 86 void |
| 145 TransmitMixer::Destroy(TransmitMixer*& mixer) | 87 TransmitMixer::Destroy(TransmitMixer*& mixer) |
| 146 { | 88 { |
| 147 if (mixer) | 89 if (mixer) |
| 148 { | 90 { |
| 149 delete mixer; | 91 delete mixer; |
| 150 mixer = NULL; | 92 mixer = NULL; |
| 151 } | 93 } |
| 152 } | 94 } |
| 153 | 95 |
| 154 TransmitMixer::TransmitMixer(uint32_t instanceId) : | 96 TransmitMixer::TransmitMixer(uint32_t instanceId) : |
| 155 // Avoid conflict with other channels by adding 1024 - 1026, | |
| 156 // won't use as much as 1024 channels. | |
| 157 _filePlayerId(instanceId + 1024), | |
| 158 _fileRecorderId(instanceId + 1025), | |
| 159 _fileCallRecorderId(instanceId + 1026), | |
| 160 #if WEBRTC_VOICE_ENGINE_TYPING_DETECTION | 97 #if WEBRTC_VOICE_ENGINE_TYPING_DETECTION |
| 161 _monitorModule(this), | 98 _monitorModule(this), |
| 162 #endif | 99 #endif |
| 163 _instanceId(instanceId) | 100 _instanceId(instanceId) |
| 164 { | 101 { |
| 165 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1), | 102 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1), |
| 166 "TransmitMixer::TransmitMixer() - ctor"); | 103 "TransmitMixer::TransmitMixer() - ctor"); |
| 167 } | 104 } |
| 168 | 105 |
| 169 TransmitMixer::~TransmitMixer() | 106 TransmitMixer::~TransmitMixer() |
| 170 { | 107 { |
| 171 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1), | 108 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1), |
| 172 "TransmitMixer::~TransmitMixer() - dtor"); | 109 "TransmitMixer::~TransmitMixer() - dtor"); |
| 173 #if WEBRTC_VOICE_ENGINE_TYPING_DETECTION | 110 #if WEBRTC_VOICE_ENGINE_TYPING_DETECTION |
| 174 if (_processThreadPtr) | 111 if (_processThreadPtr) |
| 175 _processThreadPtr->DeRegisterModule(&_monitorModule); | 112 _processThreadPtr->DeRegisterModule(&_monitorModule); |
| 176 #endif | 113 #endif |
| 177 { | |
| 178 rtc::CritScope cs(&_critSect); | |
| 179 if (file_recorder_) { | |
| 180 file_recorder_->RegisterModuleFileCallback(NULL); | |
| 181 file_recorder_->StopRecording(); | |
| 182 } | |
| 183 if (file_call_recorder_) { | |
| 184 file_call_recorder_->RegisterModuleFileCallback(NULL); | |
| 185 file_call_recorder_->StopRecording(); | |
| 186 } | |
| 187 if (file_player_) { | |
| 188 file_player_->RegisterModuleFileCallback(NULL); | |
| 189 file_player_->StopPlayingFile(); | |
| 190 } | |
| 191 } | |
| 192 } | 114 } |
| 193 | 115 |
| 194 int32_t | 116 int32_t |
| 195 TransmitMixer::SetEngineInformation(ProcessThread& processThread, | 117 TransmitMixer::SetEngineInformation(ProcessThread& processThread, |
| 196 Statistics& engineStatistics, | 118 Statistics& engineStatistics, |
| 197 ChannelManager& channelManager) | 119 ChannelManager& channelManager) |
| 198 { | 120 { |
| 199 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1), | 121 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1), |
| 200 "TransmitMixer::SetEngineInformation()"); | 122 "TransmitMixer::SetEngineInformation()"); |
| 201 | 123 |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 | 210 |
| 289 if (swap_stereo_channels_ && stereo_codec_) | 211 if (swap_stereo_channels_ && stereo_codec_) |
| 290 // Only bother swapping if we're using a stereo codec. | 212 // Only bother swapping if we're using a stereo codec. |
| 291 AudioFrameOperations::SwapStereoChannels(&_audioFrame); | 213 AudioFrameOperations::SwapStereoChannels(&_audioFrame); |
| 292 | 214 |
| 293 // --- Annoying typing detection (utilizes the APM/VAD decision) | 215 // --- Annoying typing detection (utilizes the APM/VAD decision) |
| 294 #if WEBRTC_VOICE_ENGINE_TYPING_DETECTION | 216 #if WEBRTC_VOICE_ENGINE_TYPING_DETECTION |
| 295 TypingDetection(keyPressed); | 217 TypingDetection(keyPressed); |
| 296 #endif | 218 #endif |
| 297 | 219 |
| 298 // --- Mix with file (does not affect the mixing frequency) | |
| 299 if (_filePlaying) | |
| 300 { | |
| 301 MixOrReplaceAudioWithFile(_audioFrame.sample_rate_hz_); | |
| 302 } | |
| 303 | |
| 304 // --- Record to file | |
| 305 bool file_recording = false; | |
| 306 { | |
| 307 rtc::CritScope cs(&_critSect); | |
| 308 file_recording = _fileRecording; | |
| 309 } | |
| 310 if (file_recording) | |
| 311 { | |
| 312 RecordAudioToFile(_audioFrame.sample_rate_hz_); | |
| 313 } | |
| 314 | |
| 315 // --- Measure audio level of speech after all processing. | 220 // --- Measure audio level of speech after all processing. |
| 316 double sample_duration = static_cast<double>(nSamples) / samplesPerSec; | 221 double sample_duration = static_cast<double>(nSamples) / samplesPerSec; |
| 317 _audioLevel.ComputeLevel(_audioFrame, sample_duration); | 222 _audioLevel.ComputeLevel(_audioFrame, sample_duration); |
| 318 | 223 |
| 319 return 0; | 224 return 0; |
| 320 } | 225 } |
| 321 | 226 |
| 322 void TransmitMixer::ProcessAndEncodeAudio() { | 227 void TransmitMixer::ProcessAndEncodeAudio() { |
| 323 RTC_DCHECK_GT(_audioFrame.samples_per_channel_, 0); | 228 RTC_DCHECK_GT(_audioFrame.samples_per_channel_, 0); |
| 324 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid(); | 229 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid(); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 337 | 242 |
| 338 int32_t | 243 int32_t |
| 339 TransmitMixer::StopSend() | 244 TransmitMixer::StopSend() |
| 340 { | 245 { |
| 341 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1), | 246 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1), |
| 342 "TransmitMixer::StopSend()"); | 247 "TransmitMixer::StopSend()"); |
| 343 _audioLevel.Clear(); | 248 _audioLevel.Clear(); |
| 344 return 0; | 249 return 0; |
| 345 } | 250 } |
| 346 | 251 |
| 347 int TransmitMixer::StartPlayingFileAsMicrophone(const char* fileName, | |
| 348 bool loop, | |
| 349 FileFormats format, | |
| 350 int startPosition, | |
| 351 float volumeScaling, | |
| 352 int stopPosition, | |
| 353 const CodecInst* codecInst) | |
| 354 { | |
| 355 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1), | |
| 356 "TransmitMixer::StartPlayingFileAsMicrophone(" | |
| 357 "fileNameUTF8[]=%s,loop=%d, format=%d, volumeScaling=%5.3f," | |
| 358 " startPosition=%d, stopPosition=%d)", fileName, loop, | |
| 359 format, volumeScaling, startPosition, stopPosition); | |
| 360 | |
| 361 if (_filePlaying) | |
| 362 { | |
| 363 _engineStatisticsPtr->SetLastError( | |
| 364 VE_ALREADY_PLAYING, kTraceWarning, | |
| 365 "StartPlayingFileAsMicrophone() is already playing"); | |
| 366 return 0; | |
| 367 } | |
| 368 | |
| 369 rtc::CritScope cs(&_critSect); | |
| 370 | |
| 371 // Destroy the old instance | |
| 372 if (file_player_) { | |
| 373 file_player_->RegisterModuleFileCallback(NULL); | |
| 374 file_player_.reset(); | |
| 375 } | |
| 376 | |
| 377 // Dynamically create the instance | |
| 378 file_player_ = | |
| 379 FilePlayer::CreateFilePlayer(_filePlayerId, (const FileFormats)format); | |
| 380 | |
| 381 if (!file_player_) { | |
| 382 _engineStatisticsPtr->SetLastError( | |
| 383 VE_INVALID_ARGUMENT, kTraceError, | |
| 384 "StartPlayingFileAsMicrophone() filePlayer format isnot correct"); | |
| 385 return -1; | |
| 386 } | |
| 387 | |
| 388 const uint32_t notificationTime(0); | |
| 389 | |
| 390 if (file_player_->StartPlayingFile( | |
| 391 fileName, loop, startPosition, volumeScaling, notificationTime, | |
| 392 stopPosition, (const CodecInst*)codecInst) != 0) { | |
| 393 _engineStatisticsPtr->SetLastError( | |
| 394 VE_BAD_FILE, kTraceError, | |
| 395 "StartPlayingFile() failed to start file playout"); | |
| 396 file_player_->StopPlayingFile(); | |
| 397 file_player_.reset(); | |
| 398 return -1; | |
| 399 } | |
| 400 | |
| 401 file_player_->RegisterModuleFileCallback(this); | |
| 402 _filePlaying = true; | |
| 403 | |
| 404 return 0; | |
| 405 } | |
| 406 | |
| 407 int TransmitMixer::StartPlayingFileAsMicrophone(InStream* stream, | |
| 408 FileFormats format, | |
| 409 int startPosition, | |
| 410 float volumeScaling, | |
| 411 int stopPosition, | |
| 412 const CodecInst* codecInst) | |
| 413 { | |
| 414 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1), | |
| 415 "TransmitMixer::StartPlayingFileAsMicrophone(format=%d," | |
| 416 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)", | |
| 417 format, volumeScaling, startPosition, stopPosition); | |
| 418 | |
| 419 if (stream == NULL) | |
| 420 { | |
| 421 _engineStatisticsPtr->SetLastError( | |
| 422 VE_BAD_FILE, kTraceError, | |
| 423 "StartPlayingFileAsMicrophone() NULL as input stream"); | |
| 424 return -1; | |
| 425 } | |
| 426 | |
| 427 if (_filePlaying) | |
| 428 { | |
| 429 _engineStatisticsPtr->SetLastError( | |
| 430 VE_ALREADY_PLAYING, kTraceWarning, | |
| 431 "StartPlayingFileAsMicrophone() is already playing"); | |
| 432 return 0; | |
| 433 } | |
| 434 | |
| 435 rtc::CritScope cs(&_critSect); | |
| 436 | |
| 437 // Destroy the old instance | |
| 438 if (file_player_) { | |
| 439 file_player_->RegisterModuleFileCallback(NULL); | |
| 440 file_player_.reset(); | |
| 441 } | |
| 442 | |
| 443 // Dynamically create the instance | |
| 444 file_player_ = | |
| 445 FilePlayer::CreateFilePlayer(_filePlayerId, (const FileFormats)format); | |
| 446 | |
| 447 if (!file_player_) { | |
| 448 _engineStatisticsPtr->SetLastError( | |
| 449 VE_INVALID_ARGUMENT, kTraceWarning, | |
| 450 "StartPlayingFileAsMicrophone() filePlayer format isnot correct"); | |
| 451 return -1; | |
| 452 } | |
| 453 | |
| 454 const uint32_t notificationTime(0); | |
| 455 | |
| 456 if (file_player_->StartPlayingFile(stream, startPosition, volumeScaling, | |
| 457 notificationTime, stopPosition, | |
| 458 (const CodecInst*)codecInst) != 0) { | |
| 459 _engineStatisticsPtr->SetLastError( | |
| 460 VE_BAD_FILE, kTraceError, | |
| 461 "StartPlayingFile() failed to start file playout"); | |
| 462 file_player_->StopPlayingFile(); | |
| 463 file_player_.reset(); | |
| 464 return -1; | |
| 465 } | |
| 466 file_player_->RegisterModuleFileCallback(this); | |
| 467 _filePlaying = true; | |
| 468 | |
| 469 return 0; | |
| 470 } | |
| 471 | |
| 472 int TransmitMixer::StopPlayingFileAsMicrophone() | |
| 473 { | |
| 474 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1), | |
| 475 "TransmitMixer::StopPlayingFileAsMicrophone()"); | |
| 476 | |
| 477 if (!_filePlaying) | |
| 478 { | |
| 479 return 0; | |
| 480 } | |
| 481 | |
| 482 rtc::CritScope cs(&_critSect); | |
| 483 | |
| 484 if (file_player_->StopPlayingFile() != 0) { | |
| 485 _engineStatisticsPtr->SetLastError( | |
| 486 VE_CANNOT_STOP_PLAYOUT, kTraceError, | |
| 487 "StopPlayingFile() couldnot stop playing file"); | |
| 488 return -1; | |
| 489 } | |
| 490 | |
| 491 file_player_->RegisterModuleFileCallback(NULL); | |
| 492 file_player_.reset(); | |
| 493 _filePlaying = false; | |
| 494 | |
| 495 return 0; | |
| 496 } | |
| 497 | |
| 498 int TransmitMixer::IsPlayingFileAsMicrophone() const | |
| 499 { | |
| 500 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1), | |
| 501 "TransmitMixer::IsPlayingFileAsMicrophone()"); | |
| 502 return _filePlaying; | |
| 503 } | |
| 504 | |
| 505 int TransmitMixer::StartRecordingMicrophone(const char* fileName, | |
| 506 const CodecInst* codecInst) | |
| 507 { | |
| 508 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1), | |
| 509 "TransmitMixer::StartRecordingMicrophone(fileName=%s)", | |
| 510 fileName); | |
| 511 | |
| 512 rtc::CritScope cs(&_critSect); | |
| 513 | |
| 514 if (_fileRecording) | |
| 515 { | |
| 516 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1), | |
| 517 "StartRecordingMicrophone() is already recording"); | |
| 518 return 0; | |
| 519 } | |
| 520 | |
| 521 FileFormats format; | |
| 522 const uint32_t notificationTime(0); // Not supported in VoE | |
| 523 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 }; | |
| 524 | |
| 525 if (codecInst != NULL && codecInst->channels > 2) | |
| 526 { | |
| 527 _engineStatisticsPtr->SetLastError( | |
| 528 VE_BAD_ARGUMENT, kTraceError, | |
| 529 "StartRecordingMicrophone() invalid compression"); | |
| 530 return (-1); | |
| 531 } | |
| 532 if (codecInst == NULL) | |
| 533 { | |
| 534 format = kFileFormatPcm16kHzFile; | |
| 535 codecInst = &dummyCodec; | |
| 536 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) || | |
| 537 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) || | |
| 538 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0)) | |
| 539 { | |
| 540 format = kFileFormatWavFile; | |
| 541 } else | |
| 542 { | |
| 543 format = kFileFormatCompressedFile; | |
| 544 } | |
| 545 | |
| 546 // Destroy the old instance | |
| 547 if (file_recorder_) { | |
| 548 file_recorder_->RegisterModuleFileCallback(NULL); | |
| 549 file_recorder_.reset(); | |
| 550 } | |
| 551 | |
| 552 file_recorder_ = FileRecorder::CreateFileRecorder( | |
| 553 _fileRecorderId, (const FileFormats)format); | |
| 554 if (!file_recorder_) { | |
| 555 _engineStatisticsPtr->SetLastError( | |
| 556 VE_INVALID_ARGUMENT, kTraceError, | |
| 557 "StartRecordingMicrophone() fileRecorder format isnot correct"); | |
| 558 return -1; | |
| 559 } | |
| 560 | |
| 561 if (file_recorder_->StartRecordingAudioFile( | |
| 562 fileName, (const CodecInst&)*codecInst, notificationTime) != 0) { | |
| 563 _engineStatisticsPtr->SetLastError( | |
| 564 VE_BAD_FILE, kTraceError, | |
| 565 "StartRecordingAudioFile() failed to start file recording"); | |
| 566 file_recorder_->StopRecording(); | |
| 567 file_recorder_.reset(); | |
| 568 return -1; | |
| 569 } | |
| 570 file_recorder_->RegisterModuleFileCallback(this); | |
| 571 _fileRecording = true; | |
| 572 | |
| 573 return 0; | |
| 574 } | |
| 575 | |
| 576 int TransmitMixer::StartRecordingMicrophone(OutStream* stream, | |
| 577 const CodecInst* codecInst) | |
| 578 { | |
| 579 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1), | |
| 580 "TransmitMixer::StartRecordingMicrophone()"); | |
| 581 | |
| 582 rtc::CritScope cs(&_critSect); | |
| 583 | |
| 584 if (_fileRecording) | |
| 585 { | |
| 586 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1), | |
| 587 "StartRecordingMicrophone() is already recording"); | |
| 588 return 0; | |
| 589 } | |
| 590 | |
| 591 FileFormats format; | |
| 592 const uint32_t notificationTime(0); // Not supported in VoE | |
| 593 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 }; | |
| 594 | |
| 595 if (codecInst != NULL && codecInst->channels != 1) | |
| 596 { | |
| 597 _engineStatisticsPtr->SetLastError( | |
| 598 VE_BAD_ARGUMENT, kTraceError, | |
| 599 "StartRecordingMicrophone() invalid compression"); | |
| 600 return (-1); | |
| 601 } | |
| 602 if (codecInst == NULL) | |
| 603 { | |
| 604 format = kFileFormatPcm16kHzFile; | |
| 605 codecInst = &dummyCodec; | |
| 606 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) || | |
| 607 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) || | |
| 608 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0)) | |
| 609 { | |
| 610 format = kFileFormatWavFile; | |
| 611 } else | |
| 612 { | |
| 613 format = kFileFormatCompressedFile; | |
| 614 } | |
| 615 | |
| 616 // Destroy the old instance | |
| 617 if (file_recorder_) { | |
| 618 file_recorder_->RegisterModuleFileCallback(NULL); | |
| 619 file_recorder_.reset(); | |
| 620 } | |
| 621 | |
| 622 file_recorder_ = FileRecorder::CreateFileRecorder( | |
| 623 _fileRecorderId, (const FileFormats)format); | |
| 624 if (!file_recorder_) { | |
| 625 _engineStatisticsPtr->SetLastError( | |
| 626 VE_INVALID_ARGUMENT, kTraceError, | |
| 627 "StartRecordingMicrophone() fileRecorder format isnot correct"); | |
| 628 return -1; | |
| 629 } | |
| 630 | |
| 631 if (file_recorder_->StartRecordingAudioFile(stream, *codecInst, | |
| 632 notificationTime) != 0) { | |
| 633 _engineStatisticsPtr->SetLastError( | |
| 634 VE_BAD_FILE, kTraceError, | |
| 635 "StartRecordingAudioFile() failed to start file recording"); | |
| 636 file_recorder_->StopRecording(); | |
| 637 file_recorder_.reset(); | |
| 638 return -1; | |
| 639 } | |
| 640 | |
| 641 file_recorder_->RegisterModuleFileCallback(this); | |
| 642 _fileRecording = true; | |
| 643 | |
| 644 return 0; | |
| 645 } | |
| 646 | |
| 647 | |
| 648 int TransmitMixer::StopRecordingMicrophone() | |
| 649 { | |
| 650 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1), | |
| 651 "TransmitMixer::StopRecordingMicrophone()"); | |
| 652 | |
| 653 rtc::CritScope cs(&_critSect); | |
| 654 | |
| 655 if (!_fileRecording) | |
| 656 { | |
| 657 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1), | |
| 658 "StopRecordingMicrophone() isnot recording"); | |
| 659 return 0; | |
| 660 } | |
| 661 | |
| 662 if (file_recorder_->StopRecording() != 0) { | |
| 663 _engineStatisticsPtr->SetLastError( | |
| 664 VE_STOP_RECORDING_FAILED, kTraceError, | |
| 665 "StopRecording(), could not stop recording"); | |
| 666 return -1; | |
| 667 } | |
| 668 file_recorder_->RegisterModuleFileCallback(NULL); | |
| 669 file_recorder_.reset(); | |
| 670 _fileRecording = false; | |
| 671 | |
| 672 return 0; | |
| 673 } | |
| 674 | |
| 675 int TransmitMixer::StartRecordingCall(const char* fileName, | |
| 676 const CodecInst* codecInst) | |
| 677 { | |
| 678 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1), | |
| 679 "TransmitMixer::StartRecordingCall(fileName=%s)", fileName); | |
| 680 | |
| 681 if (_fileCallRecording) | |
| 682 { | |
| 683 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1), | |
| 684 "StartRecordingCall() is already recording"); | |
| 685 return 0; | |
| 686 } | |
| 687 | |
| 688 FileFormats format; | |
| 689 const uint32_t notificationTime(0); // Not supported in VoE | |
| 690 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 }; | |
| 691 | |
| 692 if (codecInst != NULL && codecInst->channels != 1) | |
| 693 { | |
| 694 _engineStatisticsPtr->SetLastError( | |
| 695 VE_BAD_ARGUMENT, kTraceError, | |
| 696 "StartRecordingCall() invalid compression"); | |
| 697 return (-1); | |
| 698 } | |
| 699 if (codecInst == NULL) | |
| 700 { | |
| 701 format = kFileFormatPcm16kHzFile; | |
| 702 codecInst = &dummyCodec; | |
| 703 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) || | |
| 704 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) || | |
| 705 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0)) | |
| 706 { | |
| 707 format = kFileFormatWavFile; | |
| 708 } else | |
| 709 { | |
| 710 format = kFileFormatCompressedFile; | |
| 711 } | |
| 712 | |
| 713 rtc::CritScope cs(&_critSect); | |
| 714 | |
| 715 // Destroy the old instance | |
| 716 if (file_call_recorder_) { | |
| 717 file_call_recorder_->RegisterModuleFileCallback(NULL); | |
| 718 file_call_recorder_.reset(); | |
| 719 } | |
| 720 | |
| 721 file_call_recorder_ = FileRecorder::CreateFileRecorder( | |
| 722 _fileCallRecorderId, (const FileFormats)format); | |
| 723 if (!file_call_recorder_) { | |
| 724 _engineStatisticsPtr->SetLastError( | |
| 725 VE_INVALID_ARGUMENT, kTraceError, | |
| 726 "StartRecordingCall() fileRecorder format isnot correct"); | |
| 727 return -1; | |
| 728 } | |
| 729 | |
| 730 if (file_call_recorder_->StartRecordingAudioFile( | |
| 731 fileName, (const CodecInst&)*codecInst, notificationTime) != 0) { | |
| 732 _engineStatisticsPtr->SetLastError( | |
| 733 VE_BAD_FILE, kTraceError, | |
| 734 "StartRecordingAudioFile() failed to start file recording"); | |
| 735 file_call_recorder_->StopRecording(); | |
| 736 file_call_recorder_.reset(); | |
| 737 return -1; | |
| 738 } | |
| 739 file_call_recorder_->RegisterModuleFileCallback(this); | |
| 740 _fileCallRecording = true; | |
| 741 | |
| 742 return 0; | |
| 743 } | |
| 744 | |
| 745 int TransmitMixer::StartRecordingCall(OutStream* stream, | |
| 746 const CodecInst* codecInst) | |
| 747 { | |
| 748 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1), | |
| 749 "TransmitMixer::StartRecordingCall()"); | |
| 750 | |
| 751 if (_fileCallRecording) | |
| 752 { | |
| 753 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1), | |
| 754 "StartRecordingCall() is already recording"); | |
| 755 return 0; | |
| 756 } | |
| 757 | |
| 758 FileFormats format; | |
| 759 const uint32_t notificationTime(0); // Not supported in VoE | |
| 760 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 }; | |
| 761 | |
| 762 if (codecInst != NULL && codecInst->channels != 1) | |
| 763 { | |
| 764 _engineStatisticsPtr->SetLastError( | |
| 765 VE_BAD_ARGUMENT, kTraceError, | |
| 766 "StartRecordingCall() invalid compression"); | |
| 767 return (-1); | |
| 768 } | |
| 769 if (codecInst == NULL) | |
| 770 { | |
| 771 format = kFileFormatPcm16kHzFile; | |
| 772 codecInst = &dummyCodec; | |
| 773 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) || | |
| 774 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) || | |
| 775 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0)) | |
| 776 { | |
| 777 format = kFileFormatWavFile; | |
| 778 } else | |
| 779 { | |
| 780 format = kFileFormatCompressedFile; | |
| 781 } | |
| 782 | |
| 783 rtc::CritScope cs(&_critSect); | |
| 784 | |
| 785 // Destroy the old instance | |
| 786 if (file_call_recorder_) { | |
| 787 file_call_recorder_->RegisterModuleFileCallback(NULL); | |
| 788 file_call_recorder_.reset(); | |
| 789 } | |
| 790 | |
| 791 file_call_recorder_ = FileRecorder::CreateFileRecorder( | |
| 792 _fileCallRecorderId, (const FileFormats)format); | |
| 793 if (!file_call_recorder_) { | |
| 794 _engineStatisticsPtr->SetLastError( | |
| 795 VE_INVALID_ARGUMENT, kTraceError, | |
| 796 "StartRecordingCall() fileRecorder format isnot correct"); | |
| 797 return -1; | |
| 798 } | |
| 799 | |
| 800 if (file_call_recorder_->StartRecordingAudioFile(stream, *codecInst, | |
| 801 notificationTime) != 0) { | |
| 802 _engineStatisticsPtr->SetLastError( | |
| 803 VE_BAD_FILE, kTraceError, | |
| 804 "StartRecordingAudioFile() failed to start file recording"); | |
| 805 file_call_recorder_->StopRecording(); | |
| 806 file_call_recorder_.reset(); | |
| 807 return -1; | |
| 808 } | |
| 809 | |
| 810 file_call_recorder_->RegisterModuleFileCallback(this); | |
| 811 _fileCallRecording = true; | |
| 812 | |
| 813 return 0; | |
| 814 } | |
| 815 | |
| 816 int TransmitMixer::StopRecordingCall() | |
| 817 { | |
| 818 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1), | |
| 819 "TransmitMixer::StopRecordingCall()"); | |
| 820 | |
| 821 if (!_fileCallRecording) | |
| 822 { | |
| 823 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1), | |
| 824 "StopRecordingCall() file isnot recording"); | |
| 825 return -1; | |
| 826 } | |
| 827 | |
| 828 rtc::CritScope cs(&_critSect); | |
| 829 | |
| 830 if (file_call_recorder_->StopRecording() != 0) { | |
| 831 _engineStatisticsPtr->SetLastError( | |
| 832 VE_STOP_RECORDING_FAILED, kTraceError, | |
| 833 "StopRecording(), could not stop recording"); | |
| 834 return -1; | |
| 835 } | |
| 836 | |
| 837 file_call_recorder_->RegisterModuleFileCallback(NULL); | |
| 838 file_call_recorder_.reset(); | |
| 839 _fileCallRecording = false; | |
| 840 | |
| 841 return 0; | |
| 842 } | |
| 843 | |
| 844 void | |
| 845 TransmitMixer::SetMixWithMicStatus(bool mix) | |
| 846 { | |
| 847 _mixFileWithMicrophone = mix; | |
| 848 } | |
| 849 | |
| 850 int8_t TransmitMixer::AudioLevel() const | 252 int8_t TransmitMixer::AudioLevel() const |
| 851 { | 253 { |
| 852 // Speech + file level [0,9] | 254 // Speech + file level [0,9] |
| 853 return _audioLevel.Level(); | 255 return _audioLevel.Level(); |
| 854 } | 256 } |
| 855 | 257 |
| 856 int16_t TransmitMixer::AudioLevelFullRange() const | 258 int16_t TransmitMixer::AudioLevelFullRange() const |
| 857 { | 259 { |
| 858 // Speech + file level [0,32767] | 260 // Speech + file level [0,32767] |
| 859 return _audioLevel.LevelFullRange(); | 261 return _audioLevel.LevelFullRange(); |
| 860 } | 262 } |
| 861 | 263 |
| 862 double TransmitMixer::GetTotalInputEnergy() const { | 264 double TransmitMixer::GetTotalInputEnergy() const { |
| 863 return _audioLevel.TotalEnergy(); | 265 return _audioLevel.TotalEnergy(); |
| 864 } | 266 } |
| 865 | 267 |
| 866 double TransmitMixer::GetTotalInputDuration() const { | 268 double TransmitMixer::GetTotalInputDuration() const { |
| 867 return _audioLevel.TotalDuration(); | 269 return _audioLevel.TotalDuration(); |
| 868 } | 270 } |
| 869 | 271 |
| 870 bool TransmitMixer::IsRecordingCall() | |
| 871 { | |
| 872 return _fileCallRecording; | |
| 873 } | |
| 874 | |
| 875 bool TransmitMixer::IsRecordingMic() | |
| 876 { | |
| 877 rtc::CritScope cs(&_critSect); | |
| 878 return _fileRecording; | |
| 879 } | |
| 880 | |
| 881 void TransmitMixer::GenerateAudioFrame(const int16_t* audio, | 272 void TransmitMixer::GenerateAudioFrame(const int16_t* audio, |
| 882 size_t samples_per_channel, | 273 size_t samples_per_channel, |
| 883 size_t num_channels, | 274 size_t num_channels, |
| 884 int sample_rate_hz) { | 275 int sample_rate_hz) { |
| 885 int codec_rate; | 276 int codec_rate; |
| 886 size_t num_codec_channels; | 277 size_t num_codec_channels; |
| 887 GetSendCodecInfo(&codec_rate, &num_codec_channels); | 278 GetSendCodecInfo(&codec_rate, &num_codec_channels); |
| 888 stereo_codec_ = num_codec_channels == 2; | 279 stereo_codec_ = num_codec_channels == 2; |
| 889 | 280 |
| 890 // We want to process at the lowest rate possible without losing information. | 281 // We want to process at the lowest rate possible without losing information. |
| 891 // Choose the lowest native rate at least equal to the input and codec rates. | 282 // Choose the lowest native rate at least equal to the input and codec rates. |
| 892 const int min_processing_rate = std::min(sample_rate_hz, codec_rate); | 283 const int min_processing_rate = std::min(sample_rate_hz, codec_rate); |
| 893 for (size_t i = 0; i < AudioProcessing::kNumNativeSampleRates; ++i) { | 284 for (size_t i = 0; i < AudioProcessing::kNumNativeSampleRates; ++i) { |
| 894 _audioFrame.sample_rate_hz_ = AudioProcessing::kNativeSampleRatesHz[i]; | 285 _audioFrame.sample_rate_hz_ = AudioProcessing::kNativeSampleRatesHz[i]; |
| 895 if (_audioFrame.sample_rate_hz_ >= min_processing_rate) { | 286 if (_audioFrame.sample_rate_hz_ >= min_processing_rate) { |
| 896 break; | 287 break; |
| 897 } | 288 } |
| 898 } | 289 } |
| 899 _audioFrame.num_channels_ = std::min(num_channels, num_codec_channels); | 290 _audioFrame.num_channels_ = std::min(num_channels, num_codec_channels); |
| 900 RemixAndResample(audio, samples_per_channel, num_channels, sample_rate_hz, | 291 RemixAndResample(audio, samples_per_channel, num_channels, sample_rate_hz, |
| 901 &resampler_, &_audioFrame); | 292 &resampler_, &_audioFrame); |
| 902 } | 293 } |
| 903 | 294 |
| 904 int32_t TransmitMixer::RecordAudioToFile( | |
| 905 uint32_t mixingFrequency) | |
| 906 { | |
| 907 rtc::CritScope cs(&_critSect); | |
| 908 if (!file_recorder_) { | |
| 909 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1), | |
| 910 "TransmitMixer::RecordAudioToFile() filerecorder doesnot" | |
| 911 "exist"); | |
| 912 return -1; | |
| 913 } | |
| 914 | |
| 915 if (file_recorder_->RecordAudioToFile(_audioFrame) != 0) { | |
| 916 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1), | |
| 917 "TransmitMixer::RecordAudioToFile() file recording" | |
| 918 "failed"); | |
| 919 return -1; | |
| 920 } | |
| 921 | |
| 922 return 0; | |
| 923 } | |
| 924 | |
| 925 int32_t TransmitMixer::MixOrReplaceAudioWithFile( | |
| 926 int mixingFrequency) | |
| 927 { | |
| 928 std::unique_ptr<int16_t[]> fileBuffer(new int16_t[640]); | |
| 929 | |
| 930 size_t fileSamples(0); | |
| 931 { | |
| 932 rtc::CritScope cs(&_critSect); | |
| 933 if (!file_player_) { | |
| 934 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1), | |
| 935 "TransmitMixer::MixOrReplaceAudioWithFile()" | |
| 936 "fileplayer doesnot exist"); | |
| 937 return -1; | |
| 938 } | |
| 939 | |
| 940 if (file_player_->Get10msAudioFromFile(fileBuffer.get(), &fileSamples, | |
| 941 mixingFrequency) == -1) { | |
| 942 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1), | |
| 943 "TransmitMixer::MixOrReplaceAudioWithFile() file" | |
| 944 " mixing failed"); | |
| 945 return -1; | |
| 946 } | |
| 947 } | |
| 948 | |
| 949 assert(_audioFrame.samples_per_channel_ == fileSamples); | |
| 950 | |
| 951 if (_mixFileWithMicrophone) | |
| 952 { | |
| 953 // Currently file stream is always mono. | |
| 954 // TODO(xians): Change the code when FilePlayer supports real stereo. | |
| 955 MixWithSat(_audioFrame.mutable_data(), | |
| 956 _audioFrame.num_channels_, | |
| 957 fileBuffer.get(), | |
| 958 1, | |
| 959 fileSamples); | |
| 960 } else | |
| 961 { | |
| 962 // Replace ACM audio with file. | |
| 963 // Currently file stream is always mono. | |
| 964 // TODO(xians): Change the code when FilePlayer supports real stereo. | |
| 965 _audioFrame.UpdateFrame(-1, | |
| 966 0xFFFFFFFF, | |
| 967 fileBuffer.get(), | |
| 968 fileSamples, | |
| 969 mixingFrequency, | |
| 970 AudioFrame::kNormalSpeech, | |
| 971 AudioFrame::kVadUnknown, | |
| 972 1); | |
| 973 } | |
| 974 return 0; | |
| 975 } | |
| 976 | |
| 977 void TransmitMixer::ProcessAudio(int delay_ms, int clock_drift, | 295 void TransmitMixer::ProcessAudio(int delay_ms, int clock_drift, |
| 978 int current_mic_level, bool key_pressed) { | 296 int current_mic_level, bool key_pressed) { |
| 979 if (audioproc_->set_stream_delay_ms(delay_ms) != 0) { | 297 if (audioproc_->set_stream_delay_ms(delay_ms) != 0) { |
| 980 // Silently ignore this failure to avoid flooding the logs. | 298 // Silently ignore this failure to avoid flooding the logs. |
| 981 } | 299 } |
| 982 | 300 |
| 983 GainControl* agc = audioproc_->gain_control(); | 301 GainControl* agc = audioproc_->gain_control(); |
| 984 if (agc->set_stream_analog_level(current_mic_level) != 0) { | 302 if (agc->set_stream_analog_level(current_mic_level) != 0) { |
| 985 LOG(LS_ERROR) << "set_stream_analog_level failed: current_mic_level = " | 303 LOG(LS_ERROR) << "set_stream_analog_level failed: current_mic_level = " |
| 986 << current_mic_level; | 304 << current_mic_level; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1032 void TransmitMixer::EnableStereoChannelSwapping(bool enable) { | 350 void TransmitMixer::EnableStereoChannelSwapping(bool enable) { |
| 1033 swap_stereo_channels_ = enable; | 351 swap_stereo_channels_ = enable; |
| 1034 } | 352 } |
| 1035 | 353 |
| 1036 bool TransmitMixer::IsStereoChannelSwappingEnabled() { | 354 bool TransmitMixer::IsStereoChannelSwappingEnabled() { |
| 1037 return swap_stereo_channels_; | 355 return swap_stereo_channels_; |
| 1038 } | 356 } |
| 1039 | 357 |
| 1040 } // namespace voe | 358 } // namespace voe |
| 1041 } // namespace webrtc | 359 } // namespace webrtc |
| OLD | NEW |