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 |