blob: 14903501f6d4a99bbfcdf938ea2b5ecba7d67db8 [file] [log] [blame]
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001/*
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/voice_engine/transmit_mixer.h"
12
Peter Kastingdce40cf2015-08-24 14:52:23 -070013#include "webrtc/base/format_macros.h"
pbosad856222015-11-27 09:48:36 -080014#include "webrtc/base/logging.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010015#include "webrtc/modules/utility/include/audio_frame_operations.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010016#include "webrtc/system_wrappers/include/event_wrapper.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010017#include "webrtc/system_wrappers/include/trace.h"
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000018#include "webrtc/voice_engine/channel.h"
19#include "webrtc/voice_engine/channel_manager.h"
20#include "webrtc/voice_engine/include/voe_external_media.h"
21#include "webrtc/voice_engine/statistics.h"
22#include "webrtc/voice_engine/utility.h"
23#include "webrtc/voice_engine/voe_base_impl.h"
24
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000025namespace webrtc {
26namespace voe {
27
28// TODO(ajm): The thread safety of this is dubious...
29void
30TransmitMixer::OnPeriodicProcess()
31{
32 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
33 "TransmitMixer::OnPeriodicProcess()");
34
35#if defined(WEBRTC_VOICE_ENGINE_TYPING_DETECTION)
solenberg302c9782015-11-24 06:28:22 -080036 bool send_typing_noise_warning = false;
37 bool typing_noise_detected = false;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000038 {
tommi31fc21f2016-01-21 10:37:37 -080039 rtc::CritScope cs(&_critSect);
solenberg302c9782015-11-24 06:28:22 -080040 if (_typingNoiseWarningPending) {
41 send_typing_noise_warning = true;
42 typing_noise_detected = _typingNoiseDetected;
43 _typingNoiseWarningPending = false;
44 }
45 }
46 if (send_typing_noise_warning) {
tommi31fc21f2016-01-21 10:37:37 -080047 rtc::CritScope cs(&_callbackCritSect);
solenberg302c9782015-11-24 06:28:22 -080048 if (_voiceEngineObserverPtr) {
49 if (typing_noise_detected) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000050 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
51 "TransmitMixer::OnPeriodicProcess() => "
52 "CallbackOnError(VE_TYPING_NOISE_WARNING)");
53 _voiceEngineObserverPtr->CallbackOnError(
54 -1,
55 VE_TYPING_NOISE_WARNING);
56 } else {
57 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
58 "TransmitMixer::OnPeriodicProcess() => "
59 "CallbackOnError(VE_TYPING_NOISE_OFF_WARNING)");
60 _voiceEngineObserverPtr->CallbackOnError(
61 -1,
62 VE_TYPING_NOISE_OFF_WARNING);
63 }
64 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000065 }
66#endif
67
68 bool saturationWarning = false;
69 {
70 // Modify |_saturationWarning| under lock to avoid conflict with write op
71 // in ProcessAudio and also ensure that we don't hold the lock during the
72 // callback.
tommi31fc21f2016-01-21 10:37:37 -080073 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000074 saturationWarning = _saturationWarning;
75 if (_saturationWarning)
76 _saturationWarning = false;
77 }
78
79 if (saturationWarning)
80 {
tommi31fc21f2016-01-21 10:37:37 -080081 rtc::CritScope cs(&_callbackCritSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000082 if (_voiceEngineObserverPtr)
83 {
84 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
85 "TransmitMixer::OnPeriodicProcess() =>"
86 " CallbackOnError(VE_SATURATION_WARNING)");
87 _voiceEngineObserverPtr->CallbackOnError(-1, VE_SATURATION_WARNING);
88 }
89 }
90}
91
92
93void TransmitMixer::PlayNotification(int32_t id,
94 uint32_t durationMs)
95{
96 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
97 "TransmitMixer::PlayNotification(id=%d, durationMs=%d)",
98 id, durationMs);
99
100 // Not implement yet
101}
102
103void TransmitMixer::RecordNotification(int32_t id,
104 uint32_t durationMs)
105{
106 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1),
107 "TransmitMixer::RecordNotification(id=%d, durationMs=%d)",
108 id, durationMs);
109
110 // Not implement yet
111}
112
113void TransmitMixer::PlayFileEnded(int32_t id)
114{
115 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
116 "TransmitMixer::PlayFileEnded(id=%d)", id);
117
118 assert(id == _filePlayerId);
119
tommi31fc21f2016-01-21 10:37:37 -0800120 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000121
122 _filePlaying = false;
123 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1),
124 "TransmitMixer::PlayFileEnded() =>"
125 "file player module is shutdown");
126}
127
128void
129TransmitMixer::RecordFileEnded(int32_t id)
130{
131 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
132 "TransmitMixer::RecordFileEnded(id=%d)", id);
133
134 if (id == _fileRecorderId)
135 {
tommi31fc21f2016-01-21 10:37:37 -0800136 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000137 _fileRecording = false;
138 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1),
139 "TransmitMixer::RecordFileEnded() => fileRecorder module"
140 "is shutdown");
141 } else if (id == _fileCallRecorderId)
142 {
tommi31fc21f2016-01-21 10:37:37 -0800143 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000144 _fileCallRecording = false;
145 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1),
146 "TransmitMixer::RecordFileEnded() => fileCallRecorder"
147 "module is shutdown");
148 }
149}
150
151int32_t
152TransmitMixer::Create(TransmitMixer*& mixer, uint32_t instanceId)
153{
154 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, -1),
155 "TransmitMixer::Create(instanceId=%d)", instanceId);
156 mixer = new TransmitMixer(instanceId);
157 if (mixer == NULL)
158 {
159 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, -1),
160 "TransmitMixer::Create() unable to allocate memory"
161 "for mixer");
162 return -1;
163 }
164 return 0;
165}
166
167void
168TransmitMixer::Destroy(TransmitMixer*& mixer)
169{
170 if (mixer)
171 {
172 delete mixer;
173 mixer = NULL;
174 }
175}
176
177TransmitMixer::TransmitMixer(uint32_t instanceId) :
178 _engineStatisticsPtr(NULL),
179 _channelManagerPtr(NULL),
180 audioproc_(NULL),
181 _voiceEngineObserverPtr(NULL),
182 _processThreadPtr(NULL),
183 _filePlayerPtr(NULL),
184 _fileRecorderPtr(NULL),
185 _fileCallRecorderPtr(NULL),
186 // Avoid conflict with other channels by adding 1024 - 1026,
187 // won't use as much as 1024 channels.
188 _filePlayerId(instanceId + 1024),
189 _fileRecorderId(instanceId + 1025),
190 _fileCallRecorderId(instanceId + 1026),
191 _filePlaying(false),
192 _fileRecording(false),
193 _fileCallRecording(false),
194 _audioLevel(),
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000195#ifdef WEBRTC_VOICE_ENGINE_TYPING_DETECTION
196 _typingNoiseWarningPending(false),
197 _typingNoiseDetected(false),
198#endif
199 _saturationWarning(false),
200 _instanceId(instanceId),
201 _mixFileWithMicrophone(false),
202 _captureLevel(0),
203 external_postproc_ptr_(NULL),
204 external_preproc_ptr_(NULL),
205 _mute(false),
206 _remainingMuteMicTimeMs(0),
207 stereo_codec_(false),
208 swap_stereo_channels_(false)
209{
210 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1),
211 "TransmitMixer::TransmitMixer() - ctor");
212}
213
214TransmitMixer::~TransmitMixer()
215{
216 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1),
217 "TransmitMixer::~TransmitMixer() - dtor");
218 _monitorModule.DeRegisterObserver();
219 if (_processThreadPtr)
220 {
221 _processThreadPtr->DeRegisterModule(&_monitorModule);
222 }
223 DeRegisterExternalMediaProcessing(kRecordingAllChannelsMixed);
224 DeRegisterExternalMediaProcessing(kRecordingPreprocessing);
225 {
tommi31fc21f2016-01-21 10:37:37 -0800226 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000227 if (_fileRecorderPtr)
228 {
229 _fileRecorderPtr->RegisterModuleFileCallback(NULL);
230 _fileRecorderPtr->StopRecording();
231 FileRecorder::DestroyFileRecorder(_fileRecorderPtr);
232 _fileRecorderPtr = NULL;
233 }
234 if (_fileCallRecorderPtr)
235 {
236 _fileCallRecorderPtr->RegisterModuleFileCallback(NULL);
237 _fileCallRecorderPtr->StopRecording();
238 FileRecorder::DestroyFileRecorder(_fileCallRecorderPtr);
239 _fileCallRecorderPtr = NULL;
240 }
241 if (_filePlayerPtr)
242 {
243 _filePlayerPtr->RegisterModuleFileCallback(NULL);
244 _filePlayerPtr->StopPlayingFile();
245 FilePlayer::DestroyFilePlayer(_filePlayerPtr);
246 _filePlayerPtr = NULL;
247 }
248 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000249}
250
251int32_t
252TransmitMixer::SetEngineInformation(ProcessThread& processThread,
253 Statistics& engineStatistics,
254 ChannelManager& channelManager)
255{
256 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
257 "TransmitMixer::SetEngineInformation()");
258
259 _processThreadPtr = &processThread;
260 _engineStatisticsPtr = &engineStatistics;
261 _channelManagerPtr = &channelManager;
262
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000263 _processThreadPtr->RegisterModule(&_monitorModule);
264 _monitorModule.RegisterObserver(*this);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000265
266 return 0;
267}
268
269int32_t
270TransmitMixer::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
271{
272 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
273 "TransmitMixer::RegisterVoiceEngineObserver()");
tommi31fc21f2016-01-21 10:37:37 -0800274 rtc::CritScope cs(&_callbackCritSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000275
276 if (_voiceEngineObserverPtr)
277 {
278 _engineStatisticsPtr->SetLastError(
279 VE_INVALID_OPERATION, kTraceError,
280 "RegisterVoiceEngineObserver() observer already enabled");
281 return -1;
282 }
283 _voiceEngineObserverPtr = &observer;
284 return 0;
285}
286
287int32_t
288TransmitMixer::SetAudioProcessingModule(AudioProcessing* audioProcessingModule)
289{
290 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
291 "TransmitMixer::SetAudioProcessingModule("
292 "audioProcessingModule=0x%x)",
293 audioProcessingModule);
294 audioproc_ = audioProcessingModule;
295 return 0;
296}
297
Peter Kasting69558702016-01-12 16:26:35 -0800298void TransmitMixer::GetSendCodecInfo(int* max_sample_rate,
299 size_t* max_channels) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000300 *max_sample_rate = 8000;
301 *max_channels = 1;
302 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
303 it.Increment()) {
304 Channel* channel = it.GetChannel();
305 if (channel->Sending()) {
306 CodecInst codec;
307 channel->GetSendCodec(codec);
308 *max_sample_rate = std::max(*max_sample_rate, codec.plfreq);
309 *max_channels = std::max(*max_channels, codec.channels);
310 }
311 }
312}
313
314int32_t
315TransmitMixer::PrepareDemux(const void* audioSamples,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700316 size_t nSamples,
Peter Kasting69558702016-01-12 16:26:35 -0800317 size_t nChannels,
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000318 uint32_t samplesPerSec,
319 uint16_t totalDelayMS,
320 int32_t clockDrift,
321 uint16_t currentMicLevel,
322 bool keyPressed)
323{
324 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
Peter Kastingdce40cf2015-08-24 14:52:23 -0700325 "TransmitMixer::PrepareDemux(nSamples=%" PRIuS ", "
Peter Kasting69558702016-01-12 16:26:35 -0800326 "nChannels=%" PRIuS ", samplesPerSec=%u, totalDelayMS=%u, "
Peter Kastingdce40cf2015-08-24 14:52:23 -0700327 "clockDrift=%d, currentMicLevel=%u)",
328 nSamples, nChannels, samplesPerSec, totalDelayMS, clockDrift,
329 currentMicLevel);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000330
331 // --- Resample input audio and create/store the initial audio frame
332 GenerateAudioFrame(static_cast<const int16_t*>(audioSamples),
333 nSamples,
334 nChannels,
335 samplesPerSec);
336
337 {
tommi31fc21f2016-01-21 10:37:37 -0800338 rtc::CritScope cs(&_callbackCritSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000339 if (external_preproc_ptr_) {
340 external_preproc_ptr_->Process(-1, kRecordingPreprocessing,
341 _audioFrame.data_,
342 _audioFrame.samples_per_channel_,
343 _audioFrame.sample_rate_hz_,
344 _audioFrame.num_channels_ == 2);
345 }
346 }
347
348 // --- Near-end audio processing.
349 ProcessAudio(totalDelayMS, clockDrift, currentMicLevel, keyPressed);
350
351 if (swap_stereo_channels_ && stereo_codec_)
352 // Only bother swapping if we're using a stereo codec.
353 AudioFrameOperations::SwapStereoChannels(&_audioFrame);
354
355 // --- Annoying typing detection (utilizes the APM/VAD decision)
356#ifdef WEBRTC_VOICE_ENGINE_TYPING_DETECTION
357 TypingDetection(keyPressed);
358#endif
359
360 // --- Mute during DTMF tone if direct feedback is enabled
361 if (_remainingMuteMicTimeMs > 0)
362 {
363 AudioFrameOperations::Mute(_audioFrame);
364 _remainingMuteMicTimeMs -= 10;
365 if (_remainingMuteMicTimeMs < 0)
366 {
367 _remainingMuteMicTimeMs = 0;
368 }
369 }
370
371 // --- Mute signal
372 if (_mute)
373 {
374 AudioFrameOperations::Mute(_audioFrame);
375 }
376
377 // --- Mix with file (does not affect the mixing frequency)
378 if (_filePlaying)
379 {
380 MixOrReplaceAudioWithFile(_audioFrame.sample_rate_hz_);
381 }
382
383 // --- Record to file
384 bool file_recording = false;
385 {
tommi31fc21f2016-01-21 10:37:37 -0800386 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000387 file_recording = _fileRecording;
388 }
389 if (file_recording)
390 {
391 RecordAudioToFile(_audioFrame.sample_rate_hz_);
392 }
393
394 {
tommi31fc21f2016-01-21 10:37:37 -0800395 rtc::CritScope cs(&_callbackCritSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000396 if (external_postproc_ptr_) {
397 external_postproc_ptr_->Process(-1, kRecordingAllChannelsMixed,
398 _audioFrame.data_,
399 _audioFrame.samples_per_channel_,
400 _audioFrame.sample_rate_hz_,
401 _audioFrame.num_channels_ == 2);
402 }
403 }
404
405 // --- Measure audio level of speech after all processing.
406 _audioLevel.ComputeLevel(_audioFrame);
407 return 0;
408}
409
410int32_t
411TransmitMixer::DemuxAndMix()
412{
413 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
414 "TransmitMixer::DemuxAndMix()");
415
416 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
417 it.Increment())
418 {
419 Channel* channelPtr = it.GetChannel();
henrika@webrtc.org66803482014-04-17 10:45:01 +0000420 if (channelPtr->Sending())
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000421 {
422 // Demultiplex makes a copy of its input.
423 channelPtr->Demultiplex(_audioFrame);
424 channelPtr->PrepareEncodeAndSend(_audioFrame.sample_rate_hz_);
425 }
426 }
427 return 0;
428}
429
430void TransmitMixer::DemuxAndMix(const int voe_channels[],
Peter Kasting69558702016-01-12 16:26:35 -0800431 size_t number_of_voe_channels) {
432 for (size_t i = 0; i < number_of_voe_channels; ++i) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000433 voe::ChannelOwner ch = _channelManagerPtr->GetChannel(voe_channels[i]);
434 voe::Channel* channel_ptr = ch.channel();
435 if (channel_ptr) {
henrika@webrtc.org66803482014-04-17 10:45:01 +0000436 if (channel_ptr->Sending()) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000437 // Demultiplex makes a copy of its input.
438 channel_ptr->Demultiplex(_audioFrame);
439 channel_ptr->PrepareEncodeAndSend(_audioFrame.sample_rate_hz_);
440 }
441 }
442 }
443}
444
445int32_t
446TransmitMixer::EncodeAndSend()
447{
448 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
449 "TransmitMixer::EncodeAndSend()");
450
451 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
452 it.Increment())
453 {
454 Channel* channelPtr = it.GetChannel();
henrika@webrtc.org66803482014-04-17 10:45:01 +0000455 if (channelPtr->Sending())
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000456 {
457 channelPtr->EncodeAndSend();
458 }
459 }
460 return 0;
461}
462
463void TransmitMixer::EncodeAndSend(const int voe_channels[],
Peter Kasting69558702016-01-12 16:26:35 -0800464 size_t number_of_voe_channels) {
465 for (size_t i = 0; i < number_of_voe_channels; ++i) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000466 voe::ChannelOwner ch = _channelManagerPtr->GetChannel(voe_channels[i]);
467 voe::Channel* channel_ptr = ch.channel();
henrika@webrtc.org66803482014-04-17 10:45:01 +0000468 if (channel_ptr && channel_ptr->Sending())
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000469 channel_ptr->EncodeAndSend();
470 }
471}
472
473uint32_t TransmitMixer::CaptureLevel() const
474{
475 return _captureLevel;
476}
477
478void
479TransmitMixer::UpdateMuteMicrophoneTime(uint32_t lengthMs)
480{
481 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
482 "TransmitMixer::UpdateMuteMicrophoneTime(lengthMs=%d)",
483 lengthMs);
484 _remainingMuteMicTimeMs = lengthMs;
485}
486
487int32_t
488TransmitMixer::StopSend()
489{
490 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
491 "TransmitMixer::StopSend()");
492 _audioLevel.Clear();
493 return 0;
494}
495
496int TransmitMixer::StartPlayingFileAsMicrophone(const char* fileName,
497 bool loop,
498 FileFormats format,
499 int startPosition,
500 float volumeScaling,
501 int stopPosition,
502 const CodecInst* codecInst)
503{
504 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
505 "TransmitMixer::StartPlayingFileAsMicrophone("
506 "fileNameUTF8[]=%s,loop=%d, format=%d, volumeScaling=%5.3f,"
507 " startPosition=%d, stopPosition=%d)", fileName, loop,
508 format, volumeScaling, startPosition, stopPosition);
509
510 if (_filePlaying)
511 {
512 _engineStatisticsPtr->SetLastError(
513 VE_ALREADY_PLAYING, kTraceWarning,
514 "StartPlayingFileAsMicrophone() is already playing");
515 return 0;
516 }
517
tommi31fc21f2016-01-21 10:37:37 -0800518 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000519
520 // Destroy the old instance
521 if (_filePlayerPtr)
522 {
523 _filePlayerPtr->RegisterModuleFileCallback(NULL);
524 FilePlayer::DestroyFilePlayer(_filePlayerPtr);
525 _filePlayerPtr = NULL;
526 }
527
528 // Dynamically create the instance
529 _filePlayerPtr
530 = FilePlayer::CreateFilePlayer(_filePlayerId,
531 (const FileFormats) format);
532
533 if (_filePlayerPtr == NULL)
534 {
535 _engineStatisticsPtr->SetLastError(
536 VE_INVALID_ARGUMENT, kTraceError,
537 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
538 return -1;
539 }
540
541 const uint32_t notificationTime(0);
542
543 if (_filePlayerPtr->StartPlayingFile(
544 fileName,
545 loop,
546 startPosition,
547 volumeScaling,
548 notificationTime,
549 stopPosition,
550 (const CodecInst*) codecInst) != 0)
551 {
552 _engineStatisticsPtr->SetLastError(
553 VE_BAD_FILE, kTraceError,
554 "StartPlayingFile() failed to start file playout");
555 _filePlayerPtr->StopPlayingFile();
556 FilePlayer::DestroyFilePlayer(_filePlayerPtr);
557 _filePlayerPtr = NULL;
558 return -1;
559 }
560
561 _filePlayerPtr->RegisterModuleFileCallback(this);
562 _filePlaying = true;
563
564 return 0;
565}
566
567int TransmitMixer::StartPlayingFileAsMicrophone(InStream* stream,
568 FileFormats format,
569 int startPosition,
570 float volumeScaling,
571 int stopPosition,
572 const CodecInst* codecInst)
573{
574 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
575 "TransmitMixer::StartPlayingFileAsMicrophone(format=%d,"
576 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
577 format, volumeScaling, startPosition, stopPosition);
578
579 if (stream == NULL)
580 {
581 _engineStatisticsPtr->SetLastError(
582 VE_BAD_FILE, kTraceError,
583 "StartPlayingFileAsMicrophone() NULL as input stream");
584 return -1;
585 }
586
587 if (_filePlaying)
588 {
589 _engineStatisticsPtr->SetLastError(
590 VE_ALREADY_PLAYING, kTraceWarning,
591 "StartPlayingFileAsMicrophone() is already playing");
592 return 0;
593 }
594
tommi31fc21f2016-01-21 10:37:37 -0800595 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000596
597 // Destroy the old instance
598 if (_filePlayerPtr)
599 {
600 _filePlayerPtr->RegisterModuleFileCallback(NULL);
601 FilePlayer::DestroyFilePlayer(_filePlayerPtr);
602 _filePlayerPtr = NULL;
603 }
604
605 // Dynamically create the instance
606 _filePlayerPtr
607 = FilePlayer::CreateFilePlayer(_filePlayerId,
608 (const FileFormats) format);
609
610 if (_filePlayerPtr == NULL)
611 {
612 _engineStatisticsPtr->SetLastError(
613 VE_INVALID_ARGUMENT, kTraceWarning,
614 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
615 return -1;
616 }
617
618 const uint32_t notificationTime(0);
619
620 if (_filePlayerPtr->StartPlayingFile(
621 (InStream&) *stream,
622 startPosition,
623 volumeScaling,
624 notificationTime,
625 stopPosition,
626 (const CodecInst*) codecInst) != 0)
627 {
628 _engineStatisticsPtr->SetLastError(
629 VE_BAD_FILE, kTraceError,
630 "StartPlayingFile() failed to start file playout");
631 _filePlayerPtr->StopPlayingFile();
632 FilePlayer::DestroyFilePlayer(_filePlayerPtr);
633 _filePlayerPtr = NULL;
634 return -1;
635 }
636 _filePlayerPtr->RegisterModuleFileCallback(this);
637 _filePlaying = true;
638
639 return 0;
640}
641
642int TransmitMixer::StopPlayingFileAsMicrophone()
643{
644 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
645 "TransmitMixer::StopPlayingFileAsMicrophone()");
646
647 if (!_filePlaying)
648 {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000649 return 0;
650 }
651
tommi31fc21f2016-01-21 10:37:37 -0800652 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000653
654 if (_filePlayerPtr->StopPlayingFile() != 0)
655 {
656 _engineStatisticsPtr->SetLastError(
657 VE_CANNOT_STOP_PLAYOUT, kTraceError,
658 "StopPlayingFile() couldnot stop playing file");
659 return -1;
660 }
661
662 _filePlayerPtr->RegisterModuleFileCallback(NULL);
663 FilePlayer::DestroyFilePlayer(_filePlayerPtr);
664 _filePlayerPtr = NULL;
665 _filePlaying = false;
666
667 return 0;
668}
669
670int TransmitMixer::IsPlayingFileAsMicrophone() const
671{
672 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
673 "TransmitMixer::IsPlayingFileAsMicrophone()");
674 return _filePlaying;
675}
676
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000677int TransmitMixer::StartRecordingMicrophone(const char* fileName,
678 const CodecInst* codecInst)
679{
680 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
681 "TransmitMixer::StartRecordingMicrophone(fileName=%s)",
682 fileName);
683
tommi31fc21f2016-01-21 10:37:37 -0800684 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000685
686 if (_fileRecording)
687 {
688 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
689 "StartRecordingMicrophone() is already recording");
690 return 0;
691 }
692
693 FileFormats format;
694 const uint32_t notificationTime(0); // Not supported in VoE
695 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
696
Peter Kasting69558702016-01-12 16:26:35 -0800697 if (codecInst != NULL && codecInst->channels > 2)
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000698 {
699 _engineStatisticsPtr->SetLastError(
700 VE_BAD_ARGUMENT, kTraceError,
701 "StartRecordingMicrophone() invalid compression");
702 return (-1);
703 }
704 if (codecInst == NULL)
705 {
706 format = kFileFormatPcm16kHzFile;
707 codecInst = &dummyCodec;
708 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
709 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
710 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
711 {
712 format = kFileFormatWavFile;
713 } else
714 {
715 format = kFileFormatCompressedFile;
716 }
717
718 // Destroy the old instance
719 if (_fileRecorderPtr)
720 {
721 _fileRecorderPtr->RegisterModuleFileCallback(NULL);
722 FileRecorder::DestroyFileRecorder(_fileRecorderPtr);
723 _fileRecorderPtr = NULL;
724 }
725
726 _fileRecorderPtr =
727 FileRecorder::CreateFileRecorder(_fileRecorderId,
728 (const FileFormats) format);
729 if (_fileRecorderPtr == NULL)
730 {
731 _engineStatisticsPtr->SetLastError(
732 VE_INVALID_ARGUMENT, kTraceError,
733 "StartRecordingMicrophone() fileRecorder format isnot correct");
734 return -1;
735 }
736
737 if (_fileRecorderPtr->StartRecordingAudioFile(
738 fileName,
739 (const CodecInst&) *codecInst,
740 notificationTime) != 0)
741 {
742 _engineStatisticsPtr->SetLastError(
743 VE_BAD_FILE, kTraceError,
744 "StartRecordingAudioFile() failed to start file recording");
745 _fileRecorderPtr->StopRecording();
746 FileRecorder::DestroyFileRecorder(_fileRecorderPtr);
747 _fileRecorderPtr = NULL;
748 return -1;
749 }
750 _fileRecorderPtr->RegisterModuleFileCallback(this);
751 _fileRecording = true;
752
753 return 0;
754}
755
756int TransmitMixer::StartRecordingMicrophone(OutStream* stream,
757 const CodecInst* codecInst)
758{
759 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
760 "TransmitMixer::StartRecordingMicrophone()");
761
tommi31fc21f2016-01-21 10:37:37 -0800762 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000763
764 if (_fileRecording)
765 {
766 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
767 "StartRecordingMicrophone() is already recording");
768 return 0;
769 }
770
771 FileFormats format;
772 const uint32_t notificationTime(0); // Not supported in VoE
773 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
774
775 if (codecInst != NULL && codecInst->channels != 1)
776 {
777 _engineStatisticsPtr->SetLastError(
778 VE_BAD_ARGUMENT, kTraceError,
779 "StartRecordingMicrophone() invalid compression");
780 return (-1);
781 }
782 if (codecInst == NULL)
783 {
784 format = kFileFormatPcm16kHzFile;
785 codecInst = &dummyCodec;
786 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
787 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
788 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
789 {
790 format = kFileFormatWavFile;
791 } else
792 {
793 format = kFileFormatCompressedFile;
794 }
795
796 // Destroy the old instance
797 if (_fileRecorderPtr)
798 {
799 _fileRecorderPtr->RegisterModuleFileCallback(NULL);
800 FileRecorder::DestroyFileRecorder(_fileRecorderPtr);
801 _fileRecorderPtr = NULL;
802 }
803
804 _fileRecorderPtr =
805 FileRecorder::CreateFileRecorder(_fileRecorderId,
806 (const FileFormats) format);
807 if (_fileRecorderPtr == NULL)
808 {
809 _engineStatisticsPtr->SetLastError(
810 VE_INVALID_ARGUMENT, kTraceError,
811 "StartRecordingMicrophone() fileRecorder format isnot correct");
812 return -1;
813 }
814
815 if (_fileRecorderPtr->StartRecordingAudioFile(*stream,
816 *codecInst,
817 notificationTime) != 0)
818 {
819 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
820 "StartRecordingAudioFile() failed to start file recording");
821 _fileRecorderPtr->StopRecording();
822 FileRecorder::DestroyFileRecorder(_fileRecorderPtr);
823 _fileRecorderPtr = NULL;
824 return -1;
825 }
826
827 _fileRecorderPtr->RegisterModuleFileCallback(this);
828 _fileRecording = true;
829
830 return 0;
831}
832
833
834int TransmitMixer::StopRecordingMicrophone()
835{
836 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
837 "TransmitMixer::StopRecordingMicrophone()");
838
tommi31fc21f2016-01-21 10:37:37 -0800839 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000840
841 if (!_fileRecording)
842 {
843 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
844 "StopRecordingMicrophone() isnot recording");
845 return 0;
846 }
847
848 if (_fileRecorderPtr->StopRecording() != 0)
849 {
850 _engineStatisticsPtr->SetLastError(
851 VE_STOP_RECORDING_FAILED, kTraceError,
852 "StopRecording(), could not stop recording");
853 return -1;
854 }
855 _fileRecorderPtr->RegisterModuleFileCallback(NULL);
856 FileRecorder::DestroyFileRecorder(_fileRecorderPtr);
857 _fileRecorderPtr = NULL;
858 _fileRecording = false;
859
860 return 0;
861}
862
863int TransmitMixer::StartRecordingCall(const char* fileName,
864 const CodecInst* codecInst)
865{
866 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
867 "TransmitMixer::StartRecordingCall(fileName=%s)", fileName);
868
869 if (_fileCallRecording)
870 {
871 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
872 "StartRecordingCall() is already recording");
873 return 0;
874 }
875
876 FileFormats format;
877 const uint32_t notificationTime(0); // Not supported in VoE
878 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
879
880 if (codecInst != NULL && codecInst->channels != 1)
881 {
882 _engineStatisticsPtr->SetLastError(
883 VE_BAD_ARGUMENT, kTraceError,
884 "StartRecordingCall() invalid compression");
885 return (-1);
886 }
887 if (codecInst == NULL)
888 {
889 format = kFileFormatPcm16kHzFile;
890 codecInst = &dummyCodec;
891 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
892 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
893 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
894 {
895 format = kFileFormatWavFile;
896 } else
897 {
898 format = kFileFormatCompressedFile;
899 }
900
tommi31fc21f2016-01-21 10:37:37 -0800901 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000902
903 // Destroy the old instance
904 if (_fileCallRecorderPtr)
905 {
906 _fileCallRecorderPtr->RegisterModuleFileCallback(NULL);
907 FileRecorder::DestroyFileRecorder(_fileCallRecorderPtr);
908 _fileCallRecorderPtr = NULL;
909 }
910
911 _fileCallRecorderPtr
912 = FileRecorder::CreateFileRecorder(_fileCallRecorderId,
913 (const FileFormats) format);
914 if (_fileCallRecorderPtr == NULL)
915 {
916 _engineStatisticsPtr->SetLastError(
917 VE_INVALID_ARGUMENT, kTraceError,
918 "StartRecordingCall() fileRecorder format isnot correct");
919 return -1;
920 }
921
922 if (_fileCallRecorderPtr->StartRecordingAudioFile(
923 fileName,
924 (const CodecInst&) *codecInst,
925 notificationTime) != 0)
926 {
927 _engineStatisticsPtr->SetLastError(
928 VE_BAD_FILE, kTraceError,
929 "StartRecordingAudioFile() failed to start file recording");
930 _fileCallRecorderPtr->StopRecording();
931 FileRecorder::DestroyFileRecorder(_fileCallRecorderPtr);
932 _fileCallRecorderPtr = NULL;
933 return -1;
934 }
935 _fileCallRecorderPtr->RegisterModuleFileCallback(this);
936 _fileCallRecording = true;
937
938 return 0;
939}
940
941int TransmitMixer::StartRecordingCall(OutStream* stream,
942 const CodecInst* codecInst)
943{
944 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
945 "TransmitMixer::StartRecordingCall()");
946
947 if (_fileCallRecording)
948 {
949 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
950 "StartRecordingCall() is already recording");
951 return 0;
952 }
953
954 FileFormats format;
955 const uint32_t notificationTime(0); // Not supported in VoE
956 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
957
958 if (codecInst != NULL && codecInst->channels != 1)
959 {
960 _engineStatisticsPtr->SetLastError(
961 VE_BAD_ARGUMENT, kTraceError,
962 "StartRecordingCall() invalid compression");
963 return (-1);
964 }
965 if (codecInst == NULL)
966 {
967 format = kFileFormatPcm16kHzFile;
968 codecInst = &dummyCodec;
969 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
970 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
971 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
972 {
973 format = kFileFormatWavFile;
974 } else
975 {
976 format = kFileFormatCompressedFile;
977 }
978
tommi31fc21f2016-01-21 10:37:37 -0800979 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000980
981 // Destroy the old instance
982 if (_fileCallRecorderPtr)
983 {
984 _fileCallRecorderPtr->RegisterModuleFileCallback(NULL);
985 FileRecorder::DestroyFileRecorder(_fileCallRecorderPtr);
986 _fileCallRecorderPtr = NULL;
987 }
988
989 _fileCallRecorderPtr =
990 FileRecorder::CreateFileRecorder(_fileCallRecorderId,
991 (const FileFormats) format);
992 if (_fileCallRecorderPtr == NULL)
993 {
994 _engineStatisticsPtr->SetLastError(
995 VE_INVALID_ARGUMENT, kTraceError,
996 "StartRecordingCall() fileRecorder format isnot correct");
997 return -1;
998 }
999
1000 if (_fileCallRecorderPtr->StartRecordingAudioFile(*stream,
1001 *codecInst,
1002 notificationTime) != 0)
1003 {
1004 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1005 "StartRecordingAudioFile() failed to start file recording");
1006 _fileCallRecorderPtr->StopRecording();
1007 FileRecorder::DestroyFileRecorder(_fileCallRecorderPtr);
1008 _fileCallRecorderPtr = NULL;
1009 return -1;
1010 }
1011
1012 _fileCallRecorderPtr->RegisterModuleFileCallback(this);
1013 _fileCallRecording = true;
1014
1015 return 0;
1016}
1017
1018int TransmitMixer::StopRecordingCall()
1019{
1020 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
1021 "TransmitMixer::StopRecordingCall()");
1022
1023 if (!_fileCallRecording)
1024 {
1025 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
1026 "StopRecordingCall() file isnot recording");
1027 return -1;
1028 }
1029
tommi31fc21f2016-01-21 10:37:37 -08001030 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001031
1032 if (_fileCallRecorderPtr->StopRecording() != 0)
1033 {
1034 _engineStatisticsPtr->SetLastError(
1035 VE_STOP_RECORDING_FAILED, kTraceError,
1036 "StopRecording(), could not stop recording");
1037 return -1;
1038 }
1039
1040 _fileCallRecorderPtr->RegisterModuleFileCallback(NULL);
1041 FileRecorder::DestroyFileRecorder(_fileCallRecorderPtr);
1042 _fileCallRecorderPtr = NULL;
1043 _fileCallRecording = false;
1044
1045 return 0;
1046}
1047
1048void
1049TransmitMixer::SetMixWithMicStatus(bool mix)
1050{
1051 _mixFileWithMicrophone = mix;
1052}
1053
1054int TransmitMixer::RegisterExternalMediaProcessing(
1055 VoEMediaProcess* object,
1056 ProcessingTypes type) {
1057 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
1058 "TransmitMixer::RegisterExternalMediaProcessing()");
1059
tommi31fc21f2016-01-21 10:37:37 -08001060 rtc::CritScope cs(&_callbackCritSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001061 if (!object) {
1062 return -1;
1063 }
1064
1065 // Store the callback object according to the processing type.
1066 if (type == kRecordingAllChannelsMixed) {
1067 external_postproc_ptr_ = object;
1068 } else if (type == kRecordingPreprocessing) {
1069 external_preproc_ptr_ = object;
1070 } else {
1071 return -1;
1072 }
1073 return 0;
1074}
1075
1076int TransmitMixer::DeRegisterExternalMediaProcessing(ProcessingTypes type) {
1077 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
1078 "TransmitMixer::DeRegisterExternalMediaProcessing()");
1079
tommi31fc21f2016-01-21 10:37:37 -08001080 rtc::CritScope cs(&_callbackCritSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001081 if (type == kRecordingAllChannelsMixed) {
1082 external_postproc_ptr_ = NULL;
1083 } else if (type == kRecordingPreprocessing) {
1084 external_preproc_ptr_ = NULL;
1085 } else {
1086 return -1;
1087 }
1088 return 0;
1089}
1090
1091int
1092TransmitMixer::SetMute(bool enable)
1093{
1094 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
1095 "TransmitMixer::SetMute(enable=%d)", enable);
1096 _mute = enable;
1097 return 0;
1098}
1099
1100bool
1101TransmitMixer::Mute() const
1102{
1103 return _mute;
1104}
1105
1106int8_t TransmitMixer::AudioLevel() const
1107{
1108 // Speech + file level [0,9]
1109 return _audioLevel.Level();
1110}
1111
1112int16_t TransmitMixer::AudioLevelFullRange() const
1113{
1114 // Speech + file level [0,32767]
1115 return _audioLevel.LevelFullRange();
1116}
1117
1118bool TransmitMixer::IsRecordingCall()
1119{
1120 return _fileCallRecording;
1121}
1122
1123bool TransmitMixer::IsRecordingMic()
1124{
tommi31fc21f2016-01-21 10:37:37 -08001125 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001126 return _fileRecording;
1127}
1128
1129void TransmitMixer::GenerateAudioFrame(const int16_t* audio,
Peter Kastingdce40cf2015-08-24 14:52:23 -07001130 size_t samples_per_channel,
Peter Kasting69558702016-01-12 16:26:35 -08001131 size_t num_channels,
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001132 int sample_rate_hz) {
1133 int codec_rate;
Peter Kasting69558702016-01-12 16:26:35 -08001134 size_t num_codec_channels;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001135 GetSendCodecInfo(&codec_rate, &num_codec_channels);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001136 stereo_codec_ = num_codec_channels == 2;
1137
Alejandro Luebscdfe20b2015-09-23 12:49:12 -07001138 // We want to process at the lowest rate possible without losing information.
1139 // Choose the lowest native rate at least equal to the input and codec rates.
1140 const int min_processing_rate = std::min(sample_rate_hz, codec_rate);
1141 for (size_t i = 0; i < AudioProcessing::kNumNativeSampleRates; ++i) {
1142 _audioFrame.sample_rate_hz_ = AudioProcessing::kNativeSampleRatesHz[i];
1143 if (_audioFrame.sample_rate_hz_ >= min_processing_rate) {
1144 break;
1145 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001146 }
Alejandro Luebscdfe20b2015-09-23 12:49:12 -07001147 if (audioproc_->echo_control_mobile()->is_enabled()) {
1148 // AECM only supports 8 and 16 kHz.
1149 _audioFrame.sample_rate_hz_ = std::min(
1150 _audioFrame.sample_rate_hz_, AudioProcessing::kMaxAECMSampleRateHz);
1151 }
1152 _audioFrame.num_channels_ = std::min(num_channels, num_codec_channels);
1153 RemixAndResample(audio, samples_per_channel, num_channels, sample_rate_hz,
1154 &resampler_, &_audioFrame);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001155}
1156
1157int32_t TransmitMixer::RecordAudioToFile(
1158 uint32_t mixingFrequency)
1159{
tommi31fc21f2016-01-21 10:37:37 -08001160 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001161 if (_fileRecorderPtr == NULL)
1162 {
1163 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
1164 "TransmitMixer::RecordAudioToFile() filerecorder doesnot"
1165 "exist");
1166 return -1;
1167 }
1168
1169 if (_fileRecorderPtr->RecordAudioToFile(_audioFrame) != 0)
1170 {
1171 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
1172 "TransmitMixer::RecordAudioToFile() file recording"
1173 "failed");
1174 return -1;
1175 }
1176
1177 return 0;
1178}
1179
1180int32_t TransmitMixer::MixOrReplaceAudioWithFile(
1181 int mixingFrequency)
1182{
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00001183 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001184
Peter Kastingdce40cf2015-08-24 14:52:23 -07001185 size_t fileSamples(0);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001186 {
tommi31fc21f2016-01-21 10:37:37 -08001187 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001188 if (_filePlayerPtr == NULL)
1189 {
1190 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1191 VoEId(_instanceId, -1),
1192 "TransmitMixer::MixOrReplaceAudioWithFile()"
1193 "fileplayer doesnot exist");
1194 return -1;
1195 }
1196
1197 if (_filePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
1198 fileSamples,
1199 mixingFrequency) == -1)
1200 {
1201 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
1202 "TransmitMixer::MixOrReplaceAudioWithFile() file"
1203 " mixing failed");
1204 return -1;
1205 }
1206 }
1207
1208 assert(_audioFrame.samples_per_channel_ == fileSamples);
1209
1210 if (_mixFileWithMicrophone)
1211 {
1212 // Currently file stream is always mono.
1213 // TODO(xians): Change the code when FilePlayer supports real stereo.
1214 MixWithSat(_audioFrame.data_,
1215 _audioFrame.num_channels_,
1216 fileBuffer.get(),
1217 1,
1218 fileSamples);
1219 } else
1220 {
1221 // Replace ACM audio with file.
1222 // Currently file stream is always mono.
1223 // TODO(xians): Change the code when FilePlayer supports real stereo.
1224 _audioFrame.UpdateFrame(-1,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00001225 0xFFFFFFFF,
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001226 fileBuffer.get(),
1227 fileSamples,
1228 mixingFrequency,
1229 AudioFrame::kNormalSpeech,
1230 AudioFrame::kVadUnknown,
1231 1);
1232 }
1233 return 0;
1234}
1235
1236void TransmitMixer::ProcessAudio(int delay_ms, int clock_drift,
1237 int current_mic_level, bool key_pressed) {
1238 if (audioproc_->set_stream_delay_ms(delay_ms) != 0) {
pbosad856222015-11-27 09:48:36 -08001239 // Silently ignore this failure to avoid flooding the logs.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001240 }
1241
1242 GainControl* agc = audioproc_->gain_control();
1243 if (agc->set_stream_analog_level(current_mic_level) != 0) {
pbosad856222015-11-27 09:48:36 -08001244 LOG(LS_ERROR) << "set_stream_analog_level failed: current_mic_level = "
1245 << current_mic_level;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001246 assert(false);
1247 }
1248
1249 EchoCancellation* aec = audioproc_->echo_cancellation();
1250 if (aec->is_drift_compensation_enabled()) {
1251 aec->set_stream_drift_samples(clock_drift);
1252 }
1253
1254 audioproc_->set_stream_key_pressed(key_pressed);
1255
1256 int err = audioproc_->ProcessStream(&_audioFrame);
1257 if (err != 0) {
1258 LOG(LS_ERROR) << "ProcessStream() error: " << err;
1259 assert(false);
1260 }
1261
1262 // Store new capture level. Only updated when analog AGC is enabled.
1263 _captureLevel = agc->stream_analog_level();
1264
tommi31fc21f2016-01-21 10:37:37 -08001265 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001266 // Triggers a callback in OnPeriodicProcess().
1267 _saturationWarning |= agc->stream_is_saturated();
1268}
1269
1270#ifdef WEBRTC_VOICE_ENGINE_TYPING_DETECTION
1271void TransmitMixer::TypingDetection(bool keyPressed)
1272{
1273 // We let the VAD determine if we're using this feature or not.
1274 if (_audioFrame.vad_activity_ == AudioFrame::kVadUnknown) {
1275 return;
1276 }
1277
1278 bool vadActive = _audioFrame.vad_activity_ == AudioFrame::kVadActive;
1279 if (_typingDetection.Process(keyPressed, vadActive)) {
tommi31fc21f2016-01-21 10:37:37 -08001280 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001281 _typingNoiseWarningPending = true;
1282 _typingNoiseDetected = true;
1283 } else {
tommi31fc21f2016-01-21 10:37:37 -08001284 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001285 // If there is already a warning pending, do not change the state.
1286 // Otherwise set a warning pending if last callback was for noise detected.
1287 if (!_typingNoiseWarningPending && _typingNoiseDetected) {
1288 _typingNoiseWarningPending = true;
1289 _typingNoiseDetected = false;
1290 }
1291 }
1292}
1293#endif
1294
1295int TransmitMixer::GetMixingFrequency()
1296{
1297 assert(_audioFrame.sample_rate_hz_ != 0);
1298 return _audioFrame.sample_rate_hz_;
1299}
1300
1301#ifdef WEBRTC_VOICE_ENGINE_TYPING_DETECTION
1302int TransmitMixer::TimeSinceLastTyping(int &seconds)
1303{
1304 // We check in VoEAudioProcessingImpl that this is only called when
1305 // typing detection is active.
1306 seconds = _typingDetection.TimeSinceLastDetectionInSeconds();
1307 return 0;
1308}
1309#endif
1310
1311#ifdef WEBRTC_VOICE_ENGINE_TYPING_DETECTION
1312int TransmitMixer::SetTypingDetectionParameters(int timeWindow,
1313 int costPerTyping,
1314 int reportingThreshold,
1315 int penaltyDecay,
1316 int typeEventDelay)
1317{
1318 _typingDetection.SetParameters(timeWindow,
1319 costPerTyping,
1320 reportingThreshold,
1321 penaltyDecay,
1322 typeEventDelay,
1323 0);
1324 return 0;
1325}
1326#endif
1327
1328void TransmitMixer::EnableStereoChannelSwapping(bool enable) {
1329 swap_stereo_channels_ = enable;
1330}
1331
1332bool TransmitMixer::IsStereoChannelSwappingEnabled() {
1333 return swap_stereo_channels_;
1334}
1335
1336} // namespace voe
1337} // namespace webrtc