blob: e14b03f6d3c196ac47873e3d72c2d115046e6635 [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
kwibergb7f89d62016-02-17 10:04:18 -080013#include <memory>
14
aleloi6321b492016-12-05 01:46:09 -080015#include "webrtc/audio/utility/audio_frame_operations.h"
Peter Kastingdce40cf2015-08-24 14:52:23 -070016#include "webrtc/base/format_macros.h"
tommidea489f2017-03-03 03:20:24 -080017#include "webrtc/base/location.h"
pbosad856222015-11-27 09:48:36 -080018#include "webrtc/base/logging.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010019#include "webrtc/system_wrappers/include/event_wrapper.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010020#include "webrtc/system_wrappers/include/trace.h"
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000021#include "webrtc/voice_engine/channel.h"
22#include "webrtc/voice_engine/channel_manager.h"
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000023#include "webrtc/voice_engine/statistics.h"
24#include "webrtc/voice_engine/utility.h"
25#include "webrtc/voice_engine/voe_base_impl.h"
26
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000027namespace webrtc {
28namespace voe {
29
tommiba08a142017-02-28 08:25:11 -080030#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000031// TODO(ajm): The thread safety of this is dubious...
tommiba08a142017-02-28 08:25:11 -080032void TransmitMixer::OnPeriodicProcess()
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000033{
34 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
35 "TransmitMixer::OnPeriodicProcess()");
36
solenberg302c9782015-11-24 06:28:22 -080037 bool send_typing_noise_warning = false;
38 bool typing_noise_detected = false;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000039 {
tommi31fc21f2016-01-21 10:37:37 -080040 rtc::CritScope cs(&_critSect);
solenberg302c9782015-11-24 06:28:22 -080041 if (_typingNoiseWarningPending) {
42 send_typing_noise_warning = true;
43 typing_noise_detected = _typingNoiseDetected;
44 _typingNoiseWarningPending = false;
45 }
46 }
47 if (send_typing_noise_warning) {
tommi31fc21f2016-01-21 10:37:37 -080048 rtc::CritScope cs(&_callbackCritSect);
solenberg302c9782015-11-24 06:28:22 -080049 if (_voiceEngineObserverPtr) {
50 if (typing_noise_detected) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000051 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
52 "TransmitMixer::OnPeriodicProcess() => "
53 "CallbackOnError(VE_TYPING_NOISE_WARNING)");
54 _voiceEngineObserverPtr->CallbackOnError(
55 -1,
56 VE_TYPING_NOISE_WARNING);
57 } else {
58 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
59 "TransmitMixer::OnPeriodicProcess() => "
60 "CallbackOnError(VE_TYPING_NOISE_OFF_WARNING)");
61 _voiceEngineObserverPtr->CallbackOnError(
62 -1,
63 VE_TYPING_NOISE_OFF_WARNING);
64 }
65 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000066 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000067}
tommiba08a142017-02-28 08:25:11 -080068#endif // WEBRTC_VOICE_ENGINE_TYPING_DETECTION
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000069
70void 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
80void 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
90void 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
tommi31fc21f2016-01-21 10:37:37 -080097 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000098
99 _filePlaying = false;
100 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1),
101 "TransmitMixer::PlayFileEnded() =>"
102 "file player module is shutdown");
103}
104
105void
106TransmitMixer::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 {
tommi31fc21f2016-01-21 10:37:37 -0800113 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000114 _fileRecording = false;
115 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1),
116 "TransmitMixer::RecordFileEnded() => fileRecorder module"
117 "is shutdown");
118 } else if (id == _fileCallRecorderId)
119 {
tommi31fc21f2016-01-21 10:37:37 -0800120 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000121 _fileCallRecording = false;
122 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1),
123 "TransmitMixer::RecordFileEnded() => fileCallRecorder"
124 "module is shutdown");
125 }
126}
127
128int32_t
129TransmitMixer::Create(TransmitMixer*& mixer, uint32_t instanceId)
130{
131 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, -1),
132 "TransmitMixer::Create(instanceId=%d)", instanceId);
133 mixer = new TransmitMixer(instanceId);
134 if (mixer == NULL)
135 {
136 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, -1),
137 "TransmitMixer::Create() unable to allocate memory"
138 "for mixer");
139 return -1;
140 }
141 return 0;
142}
143
144void
145TransmitMixer::Destroy(TransmitMixer*& mixer)
146{
147 if (mixer)
148 {
149 delete mixer;
150 mixer = NULL;
151 }
152}
153
154TransmitMixer::TransmitMixer(uint32_t instanceId) :
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000155 // 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),
tommiba08a142017-02-28 08:25:11 -0800160#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
161 _monitorModule(this),
162#endif
solenberg76377c52017-02-21 00:54:31 -0800163 _instanceId(instanceId)
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000164{
165 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1),
166 "TransmitMixer::TransmitMixer() - ctor");
167}
168
169TransmitMixer::~TransmitMixer()
170{
171 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1),
172 "TransmitMixer::~TransmitMixer() - dtor");
tommiba08a142017-02-28 08:25:11 -0800173#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000174 if (_processThreadPtr)
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000175 _processThreadPtr->DeRegisterModule(&_monitorModule);
tommiba08a142017-02-28 08:25:11 -0800176#endif
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000177 {
tommi31fc21f2016-01-21 10:37:37 -0800178 rtc::CritScope cs(&_critSect);
kwiberg5a25d952016-08-17 07:31:12 -0700179 if (file_recorder_) {
180 file_recorder_->RegisterModuleFileCallback(NULL);
181 file_recorder_->StopRecording();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000182 }
kwiberg5a25d952016-08-17 07:31:12 -0700183 if (file_call_recorder_) {
184 file_call_recorder_->RegisterModuleFileCallback(NULL);
185 file_call_recorder_->StopRecording();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000186 }
kwiberg5a25d952016-08-17 07:31:12 -0700187 if (file_player_) {
188 file_player_->RegisterModuleFileCallback(NULL);
189 file_player_->StopPlayingFile();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000190 }
191 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000192}
193
194int32_t
195TransmitMixer::SetEngineInformation(ProcessThread& processThread,
196 Statistics& engineStatistics,
197 ChannelManager& channelManager)
198{
199 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
200 "TransmitMixer::SetEngineInformation()");
201
202 _processThreadPtr = &processThread;
203 _engineStatisticsPtr = &engineStatistics;
204 _channelManagerPtr = &channelManager;
205
tommiba08a142017-02-28 08:25:11 -0800206#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
tommidea489f2017-03-03 03:20:24 -0800207 _processThreadPtr->RegisterModule(&_monitorModule, RTC_FROM_HERE);
tommiba08a142017-02-28 08:25:11 -0800208#endif
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000209 return 0;
210}
211
212int32_t
213TransmitMixer::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
214{
215 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
216 "TransmitMixer::RegisterVoiceEngineObserver()");
tommi31fc21f2016-01-21 10:37:37 -0800217 rtc::CritScope cs(&_callbackCritSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000218
219 if (_voiceEngineObserverPtr)
220 {
221 _engineStatisticsPtr->SetLastError(
222 VE_INVALID_OPERATION, kTraceError,
223 "RegisterVoiceEngineObserver() observer already enabled");
224 return -1;
225 }
226 _voiceEngineObserverPtr = &observer;
227 return 0;
228}
229
230int32_t
231TransmitMixer::SetAudioProcessingModule(AudioProcessing* audioProcessingModule)
232{
233 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
234 "TransmitMixer::SetAudioProcessingModule("
235 "audioProcessingModule=0x%x)",
236 audioProcessingModule);
237 audioproc_ = audioProcessingModule;
238 return 0;
239}
240
Peter Kasting69558702016-01-12 16:26:35 -0800241void TransmitMixer::GetSendCodecInfo(int* max_sample_rate,
242 size_t* max_channels) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000243 *max_sample_rate = 8000;
244 *max_channels = 1;
245 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
246 it.Increment()) {
247 Channel* channel = it.GetChannel();
248 if (channel->Sending()) {
249 CodecInst codec;
250 channel->GetSendCodec(codec);
251 *max_sample_rate = std::max(*max_sample_rate, codec.plfreq);
252 *max_channels = std::max(*max_channels, codec.channels);
253 }
254 }
255}
256
257int32_t
258TransmitMixer::PrepareDemux(const void* audioSamples,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700259 size_t nSamples,
Peter Kasting69558702016-01-12 16:26:35 -0800260 size_t nChannels,
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000261 uint32_t samplesPerSec,
262 uint16_t totalDelayMS,
263 int32_t clockDrift,
264 uint16_t currentMicLevel,
265 bool keyPressed)
266{
267 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
Peter Kastingdce40cf2015-08-24 14:52:23 -0700268 "TransmitMixer::PrepareDemux(nSamples=%" PRIuS ", "
Peter Kasting69558702016-01-12 16:26:35 -0800269 "nChannels=%" PRIuS ", samplesPerSec=%u, totalDelayMS=%u, "
Peter Kastingdce40cf2015-08-24 14:52:23 -0700270 "clockDrift=%d, currentMicLevel=%u)",
271 nSamples, nChannels, samplesPerSec, totalDelayMS, clockDrift,
272 currentMicLevel);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000273
274 // --- Resample input audio and create/store the initial audio frame
275 GenerateAudioFrame(static_cast<const int16_t*>(audioSamples),
276 nSamples,
277 nChannels,
278 samplesPerSec);
279
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000280 // --- Near-end audio processing.
281 ProcessAudio(totalDelayMS, clockDrift, currentMicLevel, keyPressed);
282
283 if (swap_stereo_channels_ && stereo_codec_)
284 // Only bother swapping if we're using a stereo codec.
285 AudioFrameOperations::SwapStereoChannels(&_audioFrame);
286
287 // --- Annoying typing detection (utilizes the APM/VAD decision)
henrik.lundinf00082d2016-12-05 02:22:12 -0800288#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000289 TypingDetection(keyPressed);
290#endif
291
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000292 // --- Mix with file (does not affect the mixing frequency)
293 if (_filePlaying)
294 {
295 MixOrReplaceAudioWithFile(_audioFrame.sample_rate_hz_);
296 }
297
298 // --- Record to file
299 bool file_recording = false;
300 {
tommi31fc21f2016-01-21 10:37:37 -0800301 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000302 file_recording = _fileRecording;
303 }
304 if (file_recording)
305 {
306 RecordAudioToFile(_audioFrame.sample_rate_hz_);
307 }
308
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000309 // --- Measure audio level of speech after all processing.
310 _audioLevel.ComputeLevel(_audioFrame);
311 return 0;
312}
313
henrikaec6fbd22017-03-31 05:43:36 -0700314void TransmitMixer::ProcessAndEncodeAudio() {
315 RTC_DCHECK_GT(_audioFrame.samples_per_channel_, 0);
316 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
317 it.Increment()) {
318 Channel* const channel = it.GetChannel();
319 if (channel->Sending()) {
320 channel->ProcessAndEncodeAudio(_audioFrame);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000321 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000322 }
323}
324
325uint32_t TransmitMixer::CaptureLevel() const
326{
327 return _captureLevel;
328}
329
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000330int32_t
331TransmitMixer::StopSend()
332{
333 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
334 "TransmitMixer::StopSend()");
335 _audioLevel.Clear();
336 return 0;
337}
338
339int TransmitMixer::StartPlayingFileAsMicrophone(const char* fileName,
340 bool loop,
341 FileFormats format,
342 int startPosition,
343 float volumeScaling,
344 int stopPosition,
345 const CodecInst* codecInst)
346{
347 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
348 "TransmitMixer::StartPlayingFileAsMicrophone("
349 "fileNameUTF8[]=%s,loop=%d, format=%d, volumeScaling=%5.3f,"
350 " startPosition=%d, stopPosition=%d)", fileName, loop,
351 format, volumeScaling, startPosition, stopPosition);
352
353 if (_filePlaying)
354 {
355 _engineStatisticsPtr->SetLastError(
356 VE_ALREADY_PLAYING, kTraceWarning,
357 "StartPlayingFileAsMicrophone() is already playing");
358 return 0;
359 }
360
tommi31fc21f2016-01-21 10:37:37 -0800361 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000362
363 // Destroy the old instance
kwiberg5a25d952016-08-17 07:31:12 -0700364 if (file_player_) {
365 file_player_->RegisterModuleFileCallback(NULL);
366 file_player_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000367 }
368
369 // Dynamically create the instance
kwiberg5a25d952016-08-17 07:31:12 -0700370 file_player_ =
kwiberg5b356f42016-09-08 04:32:33 -0700371 FilePlayer::CreateFilePlayer(_filePlayerId, (const FileFormats)format);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000372
kwiberg5a25d952016-08-17 07:31:12 -0700373 if (!file_player_) {
374 _engineStatisticsPtr->SetLastError(
375 VE_INVALID_ARGUMENT, kTraceError,
376 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
377 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000378 }
379
380 const uint32_t notificationTime(0);
381
kwiberg5a25d952016-08-17 07:31:12 -0700382 if (file_player_->StartPlayingFile(
383 fileName, loop, startPosition, volumeScaling, notificationTime,
384 stopPosition, (const CodecInst*)codecInst) != 0) {
385 _engineStatisticsPtr->SetLastError(
386 VE_BAD_FILE, kTraceError,
387 "StartPlayingFile() failed to start file playout");
388 file_player_->StopPlayingFile();
389 file_player_.reset();
390 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000391 }
392
kwiberg5a25d952016-08-17 07:31:12 -0700393 file_player_->RegisterModuleFileCallback(this);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000394 _filePlaying = true;
395
396 return 0;
397}
398
399int TransmitMixer::StartPlayingFileAsMicrophone(InStream* stream,
400 FileFormats format,
401 int startPosition,
402 float volumeScaling,
403 int stopPosition,
404 const CodecInst* codecInst)
405{
406 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
407 "TransmitMixer::StartPlayingFileAsMicrophone(format=%d,"
408 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
409 format, volumeScaling, startPosition, stopPosition);
410
411 if (stream == NULL)
412 {
413 _engineStatisticsPtr->SetLastError(
414 VE_BAD_FILE, kTraceError,
415 "StartPlayingFileAsMicrophone() NULL as input stream");
416 return -1;
417 }
418
419 if (_filePlaying)
420 {
421 _engineStatisticsPtr->SetLastError(
422 VE_ALREADY_PLAYING, kTraceWarning,
423 "StartPlayingFileAsMicrophone() is already playing");
424 return 0;
425 }
426
tommi31fc21f2016-01-21 10:37:37 -0800427 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000428
429 // Destroy the old instance
kwiberg5a25d952016-08-17 07:31:12 -0700430 if (file_player_) {
431 file_player_->RegisterModuleFileCallback(NULL);
432 file_player_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000433 }
434
435 // Dynamically create the instance
kwiberg5a25d952016-08-17 07:31:12 -0700436 file_player_ =
kwiberg5b356f42016-09-08 04:32:33 -0700437 FilePlayer::CreateFilePlayer(_filePlayerId, (const FileFormats)format);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000438
kwiberg5a25d952016-08-17 07:31:12 -0700439 if (!file_player_) {
440 _engineStatisticsPtr->SetLastError(
441 VE_INVALID_ARGUMENT, kTraceWarning,
442 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
443 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000444 }
445
446 const uint32_t notificationTime(0);
447
kwiberg4ec01d92016-08-22 08:43:54 -0700448 if (file_player_->StartPlayingFile(stream, startPosition, volumeScaling,
449 notificationTime, stopPosition,
450 (const CodecInst*)codecInst) != 0) {
kwiberg5a25d952016-08-17 07:31:12 -0700451 _engineStatisticsPtr->SetLastError(
452 VE_BAD_FILE, kTraceError,
453 "StartPlayingFile() failed to start file playout");
454 file_player_->StopPlayingFile();
455 file_player_.reset();
456 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000457 }
kwiberg5a25d952016-08-17 07:31:12 -0700458 file_player_->RegisterModuleFileCallback(this);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000459 _filePlaying = true;
460
461 return 0;
462}
463
464int TransmitMixer::StopPlayingFileAsMicrophone()
465{
466 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
467 "TransmitMixer::StopPlayingFileAsMicrophone()");
468
469 if (!_filePlaying)
470 {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000471 return 0;
472 }
473
tommi31fc21f2016-01-21 10:37:37 -0800474 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000475
kwiberg5a25d952016-08-17 07:31:12 -0700476 if (file_player_->StopPlayingFile() != 0) {
477 _engineStatisticsPtr->SetLastError(
478 VE_CANNOT_STOP_PLAYOUT, kTraceError,
479 "StopPlayingFile() couldnot stop playing file");
480 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000481 }
482
kwiberg5a25d952016-08-17 07:31:12 -0700483 file_player_->RegisterModuleFileCallback(NULL);
484 file_player_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000485 _filePlaying = false;
486
487 return 0;
488}
489
490int TransmitMixer::IsPlayingFileAsMicrophone() const
491{
492 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
493 "TransmitMixer::IsPlayingFileAsMicrophone()");
494 return _filePlaying;
495}
496
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000497int TransmitMixer::StartRecordingMicrophone(const char* fileName,
498 const CodecInst* codecInst)
499{
500 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
501 "TransmitMixer::StartRecordingMicrophone(fileName=%s)",
502 fileName);
503
tommi31fc21f2016-01-21 10:37:37 -0800504 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000505
506 if (_fileRecording)
507 {
508 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
509 "StartRecordingMicrophone() is already recording");
510 return 0;
511 }
512
513 FileFormats format;
514 const uint32_t notificationTime(0); // Not supported in VoE
515 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
516
Peter Kasting69558702016-01-12 16:26:35 -0800517 if (codecInst != NULL && codecInst->channels > 2)
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000518 {
519 _engineStatisticsPtr->SetLastError(
520 VE_BAD_ARGUMENT, kTraceError,
521 "StartRecordingMicrophone() invalid compression");
522 return (-1);
523 }
524 if (codecInst == NULL)
525 {
526 format = kFileFormatPcm16kHzFile;
527 codecInst = &dummyCodec;
528 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
529 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
530 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
531 {
532 format = kFileFormatWavFile;
533 } else
534 {
535 format = kFileFormatCompressedFile;
536 }
537
538 // Destroy the old instance
kwiberg5a25d952016-08-17 07:31:12 -0700539 if (file_recorder_) {
540 file_recorder_->RegisterModuleFileCallback(NULL);
541 file_recorder_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000542 }
543
kwiberg5a25d952016-08-17 07:31:12 -0700544 file_recorder_ = FileRecorder::CreateFileRecorder(
545 _fileRecorderId, (const FileFormats)format);
546 if (!file_recorder_) {
547 _engineStatisticsPtr->SetLastError(
548 VE_INVALID_ARGUMENT, kTraceError,
549 "StartRecordingMicrophone() fileRecorder format isnot correct");
550 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000551 }
552
kwiberg5a25d952016-08-17 07:31:12 -0700553 if (file_recorder_->StartRecordingAudioFile(
554 fileName, (const CodecInst&)*codecInst, notificationTime) != 0) {
555 _engineStatisticsPtr->SetLastError(
556 VE_BAD_FILE, kTraceError,
557 "StartRecordingAudioFile() failed to start file recording");
558 file_recorder_->StopRecording();
559 file_recorder_.reset();
560 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000561 }
kwiberg5a25d952016-08-17 07:31:12 -0700562 file_recorder_->RegisterModuleFileCallback(this);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000563 _fileRecording = true;
564
565 return 0;
566}
567
568int TransmitMixer::StartRecordingMicrophone(OutStream* stream,
569 const CodecInst* codecInst)
570{
571 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
572 "TransmitMixer::StartRecordingMicrophone()");
573
tommi31fc21f2016-01-21 10:37:37 -0800574 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000575
576 if (_fileRecording)
577 {
578 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
579 "StartRecordingMicrophone() is already recording");
580 return 0;
581 }
582
583 FileFormats format;
584 const uint32_t notificationTime(0); // Not supported in VoE
585 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
586
587 if (codecInst != NULL && codecInst->channels != 1)
588 {
589 _engineStatisticsPtr->SetLastError(
590 VE_BAD_ARGUMENT, kTraceError,
591 "StartRecordingMicrophone() invalid compression");
592 return (-1);
593 }
594 if (codecInst == NULL)
595 {
596 format = kFileFormatPcm16kHzFile;
597 codecInst = &dummyCodec;
598 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
599 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
600 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
601 {
602 format = kFileFormatWavFile;
603 } else
604 {
605 format = kFileFormatCompressedFile;
606 }
607
608 // Destroy the old instance
kwiberg5a25d952016-08-17 07:31:12 -0700609 if (file_recorder_) {
610 file_recorder_->RegisterModuleFileCallback(NULL);
611 file_recorder_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000612 }
613
kwiberg5a25d952016-08-17 07:31:12 -0700614 file_recorder_ = FileRecorder::CreateFileRecorder(
615 _fileRecorderId, (const FileFormats)format);
616 if (!file_recorder_) {
617 _engineStatisticsPtr->SetLastError(
618 VE_INVALID_ARGUMENT, kTraceError,
619 "StartRecordingMicrophone() fileRecorder format isnot correct");
620 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000621 }
622
kwiberg4ec01d92016-08-22 08:43:54 -0700623 if (file_recorder_->StartRecordingAudioFile(stream, *codecInst,
kwiberg5a25d952016-08-17 07:31:12 -0700624 notificationTime) != 0) {
625 _engineStatisticsPtr->SetLastError(
626 VE_BAD_FILE, kTraceError,
627 "StartRecordingAudioFile() failed to start file recording");
628 file_recorder_->StopRecording();
629 file_recorder_.reset();
630 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000631 }
632
kwiberg5a25d952016-08-17 07:31:12 -0700633 file_recorder_->RegisterModuleFileCallback(this);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000634 _fileRecording = true;
635
636 return 0;
637}
638
639
640int TransmitMixer::StopRecordingMicrophone()
641{
642 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
643 "TransmitMixer::StopRecordingMicrophone()");
644
tommi31fc21f2016-01-21 10:37:37 -0800645 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000646
647 if (!_fileRecording)
648 {
649 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
650 "StopRecordingMicrophone() isnot recording");
651 return 0;
652 }
653
kwiberg5a25d952016-08-17 07:31:12 -0700654 if (file_recorder_->StopRecording() != 0) {
655 _engineStatisticsPtr->SetLastError(
656 VE_STOP_RECORDING_FAILED, kTraceError,
657 "StopRecording(), could not stop recording");
658 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000659 }
kwiberg5a25d952016-08-17 07:31:12 -0700660 file_recorder_->RegisterModuleFileCallback(NULL);
661 file_recorder_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000662 _fileRecording = false;
663
664 return 0;
665}
666
667int TransmitMixer::StartRecordingCall(const char* fileName,
668 const CodecInst* codecInst)
669{
670 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
671 "TransmitMixer::StartRecordingCall(fileName=%s)", fileName);
672
673 if (_fileCallRecording)
674 {
675 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
676 "StartRecordingCall() is already recording");
677 return 0;
678 }
679
680 FileFormats format;
681 const uint32_t notificationTime(0); // Not supported in VoE
682 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
683
684 if (codecInst != NULL && codecInst->channels != 1)
685 {
686 _engineStatisticsPtr->SetLastError(
687 VE_BAD_ARGUMENT, kTraceError,
688 "StartRecordingCall() invalid compression");
689 return (-1);
690 }
691 if (codecInst == NULL)
692 {
693 format = kFileFormatPcm16kHzFile;
694 codecInst = &dummyCodec;
695 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
696 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
697 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
698 {
699 format = kFileFormatWavFile;
700 } else
701 {
702 format = kFileFormatCompressedFile;
703 }
704
tommi31fc21f2016-01-21 10:37:37 -0800705 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000706
707 // Destroy the old instance
kwiberg5a25d952016-08-17 07:31:12 -0700708 if (file_call_recorder_) {
709 file_call_recorder_->RegisterModuleFileCallback(NULL);
710 file_call_recorder_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000711 }
712
kwiberg5a25d952016-08-17 07:31:12 -0700713 file_call_recorder_ = FileRecorder::CreateFileRecorder(
714 _fileCallRecorderId, (const FileFormats)format);
715 if (!file_call_recorder_) {
716 _engineStatisticsPtr->SetLastError(
717 VE_INVALID_ARGUMENT, kTraceError,
718 "StartRecordingCall() fileRecorder format isnot correct");
719 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000720 }
721
kwiberg5a25d952016-08-17 07:31:12 -0700722 if (file_call_recorder_->StartRecordingAudioFile(
723 fileName, (const CodecInst&)*codecInst, notificationTime) != 0) {
724 _engineStatisticsPtr->SetLastError(
725 VE_BAD_FILE, kTraceError,
726 "StartRecordingAudioFile() failed to start file recording");
727 file_call_recorder_->StopRecording();
728 file_call_recorder_.reset();
729 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000730 }
kwiberg5a25d952016-08-17 07:31:12 -0700731 file_call_recorder_->RegisterModuleFileCallback(this);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000732 _fileCallRecording = true;
733
734 return 0;
735}
736
737int TransmitMixer::StartRecordingCall(OutStream* stream,
738 const CodecInst* codecInst)
739{
740 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
741 "TransmitMixer::StartRecordingCall()");
742
743 if (_fileCallRecording)
744 {
745 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
746 "StartRecordingCall() is already recording");
747 return 0;
748 }
749
750 FileFormats format;
751 const uint32_t notificationTime(0); // Not supported in VoE
752 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
753
754 if (codecInst != NULL && codecInst->channels != 1)
755 {
756 _engineStatisticsPtr->SetLastError(
757 VE_BAD_ARGUMENT, kTraceError,
758 "StartRecordingCall() invalid compression");
759 return (-1);
760 }
761 if (codecInst == NULL)
762 {
763 format = kFileFormatPcm16kHzFile;
764 codecInst = &dummyCodec;
765 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
766 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
767 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
768 {
769 format = kFileFormatWavFile;
770 } else
771 {
772 format = kFileFormatCompressedFile;
773 }
774
tommi31fc21f2016-01-21 10:37:37 -0800775 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000776
777 // Destroy the old instance
kwiberg5a25d952016-08-17 07:31:12 -0700778 if (file_call_recorder_) {
779 file_call_recorder_->RegisterModuleFileCallback(NULL);
780 file_call_recorder_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000781 }
782
kwiberg5a25d952016-08-17 07:31:12 -0700783 file_call_recorder_ = FileRecorder::CreateFileRecorder(
784 _fileCallRecorderId, (const FileFormats)format);
785 if (!file_call_recorder_) {
786 _engineStatisticsPtr->SetLastError(
787 VE_INVALID_ARGUMENT, kTraceError,
788 "StartRecordingCall() fileRecorder format isnot correct");
789 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000790 }
791
kwiberg4ec01d92016-08-22 08:43:54 -0700792 if (file_call_recorder_->StartRecordingAudioFile(stream, *codecInst,
kwiberg5a25d952016-08-17 07:31:12 -0700793 notificationTime) != 0) {
794 _engineStatisticsPtr->SetLastError(
795 VE_BAD_FILE, kTraceError,
796 "StartRecordingAudioFile() failed to start file recording");
797 file_call_recorder_->StopRecording();
798 file_call_recorder_.reset();
799 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000800 }
801
kwiberg5a25d952016-08-17 07:31:12 -0700802 file_call_recorder_->RegisterModuleFileCallback(this);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000803 _fileCallRecording = true;
804
805 return 0;
806}
807
808int TransmitMixer::StopRecordingCall()
809{
810 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
811 "TransmitMixer::StopRecordingCall()");
812
813 if (!_fileCallRecording)
814 {
815 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
816 "StopRecordingCall() file isnot recording");
817 return -1;
818 }
819
tommi31fc21f2016-01-21 10:37:37 -0800820 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000821
kwiberg5a25d952016-08-17 07:31:12 -0700822 if (file_call_recorder_->StopRecording() != 0) {
823 _engineStatisticsPtr->SetLastError(
824 VE_STOP_RECORDING_FAILED, kTraceError,
825 "StopRecording(), could not stop recording");
826 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000827 }
828
kwiberg5a25d952016-08-17 07:31:12 -0700829 file_call_recorder_->RegisterModuleFileCallback(NULL);
830 file_call_recorder_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000831 _fileCallRecording = false;
832
833 return 0;
834}
835
836void
837TransmitMixer::SetMixWithMicStatus(bool mix)
838{
839 _mixFileWithMicrophone = mix;
840}
841
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000842int8_t TransmitMixer::AudioLevel() const
843{
844 // Speech + file level [0,9]
845 return _audioLevel.Level();
846}
847
848int16_t TransmitMixer::AudioLevelFullRange() const
849{
850 // Speech + file level [0,32767]
851 return _audioLevel.LevelFullRange();
852}
853
854bool TransmitMixer::IsRecordingCall()
855{
856 return _fileCallRecording;
857}
858
859bool TransmitMixer::IsRecordingMic()
860{
tommi31fc21f2016-01-21 10:37:37 -0800861 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000862 return _fileRecording;
863}
864
865void TransmitMixer::GenerateAudioFrame(const int16_t* audio,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700866 size_t samples_per_channel,
Peter Kasting69558702016-01-12 16:26:35 -0800867 size_t num_channels,
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000868 int sample_rate_hz) {
869 int codec_rate;
Peter Kasting69558702016-01-12 16:26:35 -0800870 size_t num_codec_channels;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000871 GetSendCodecInfo(&codec_rate, &num_codec_channels);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000872 stereo_codec_ = num_codec_channels == 2;
873
Alejandro Luebscdfe20b2015-09-23 12:49:12 -0700874 // We want to process at the lowest rate possible without losing information.
875 // Choose the lowest native rate at least equal to the input and codec rates.
876 const int min_processing_rate = std::min(sample_rate_hz, codec_rate);
877 for (size_t i = 0; i < AudioProcessing::kNumNativeSampleRates; ++i) {
878 _audioFrame.sample_rate_hz_ = AudioProcessing::kNativeSampleRatesHz[i];
879 if (_audioFrame.sample_rate_hz_ >= min_processing_rate) {
880 break;
881 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000882 }
Alejandro Luebscdfe20b2015-09-23 12:49:12 -0700883 _audioFrame.num_channels_ = std::min(num_channels, num_codec_channels);
884 RemixAndResample(audio, samples_per_channel, num_channels, sample_rate_hz,
885 &resampler_, &_audioFrame);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000886}
887
888int32_t TransmitMixer::RecordAudioToFile(
889 uint32_t mixingFrequency)
890{
tommi31fc21f2016-01-21 10:37:37 -0800891 rtc::CritScope cs(&_critSect);
kwiberg5a25d952016-08-17 07:31:12 -0700892 if (!file_recorder_) {
893 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
894 "TransmitMixer::RecordAudioToFile() filerecorder doesnot"
895 "exist");
896 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000897 }
898
kwiberg5a25d952016-08-17 07:31:12 -0700899 if (file_recorder_->RecordAudioToFile(_audioFrame) != 0) {
900 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
901 "TransmitMixer::RecordAudioToFile() file recording"
902 "failed");
903 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000904 }
905
906 return 0;
907}
908
909int32_t TransmitMixer::MixOrReplaceAudioWithFile(
910 int mixingFrequency)
911{
kwibergb7f89d62016-02-17 10:04:18 -0800912 std::unique_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000913
Peter Kastingdce40cf2015-08-24 14:52:23 -0700914 size_t fileSamples(0);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000915 {
tommi31fc21f2016-01-21 10:37:37 -0800916 rtc::CritScope cs(&_critSect);
kwiberg5a25d952016-08-17 07:31:12 -0700917 if (!file_player_) {
918 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
919 "TransmitMixer::MixOrReplaceAudioWithFile()"
920 "fileplayer doesnot exist");
921 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000922 }
923
kwiberg4ec01d92016-08-22 08:43:54 -0700924 if (file_player_->Get10msAudioFromFile(fileBuffer.get(), &fileSamples,
kwiberg5a25d952016-08-17 07:31:12 -0700925 mixingFrequency) == -1) {
926 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
927 "TransmitMixer::MixOrReplaceAudioWithFile() file"
928 " mixing failed");
929 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000930 }
931 }
932
933 assert(_audioFrame.samples_per_channel_ == fileSamples);
934
935 if (_mixFileWithMicrophone)
936 {
937 // Currently file stream is always mono.
938 // TODO(xians): Change the code when FilePlayer supports real stereo.
939 MixWithSat(_audioFrame.data_,
940 _audioFrame.num_channels_,
941 fileBuffer.get(),
942 1,
943 fileSamples);
944 } else
945 {
946 // Replace ACM audio with file.
947 // Currently file stream is always mono.
948 // TODO(xians): Change the code when FilePlayer supports real stereo.
949 _audioFrame.UpdateFrame(-1,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000950 0xFFFFFFFF,
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000951 fileBuffer.get(),
952 fileSamples,
953 mixingFrequency,
954 AudioFrame::kNormalSpeech,
955 AudioFrame::kVadUnknown,
956 1);
957 }
958 return 0;
959}
960
961void TransmitMixer::ProcessAudio(int delay_ms, int clock_drift,
962 int current_mic_level, bool key_pressed) {
963 if (audioproc_->set_stream_delay_ms(delay_ms) != 0) {
pbosad856222015-11-27 09:48:36 -0800964 // Silently ignore this failure to avoid flooding the logs.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000965 }
966
967 GainControl* agc = audioproc_->gain_control();
968 if (agc->set_stream_analog_level(current_mic_level) != 0) {
pbosad856222015-11-27 09:48:36 -0800969 LOG(LS_ERROR) << "set_stream_analog_level failed: current_mic_level = "
970 << current_mic_level;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000971 assert(false);
972 }
973
974 EchoCancellation* aec = audioproc_->echo_cancellation();
975 if (aec->is_drift_compensation_enabled()) {
976 aec->set_stream_drift_samples(clock_drift);
977 }
978
979 audioproc_->set_stream_key_pressed(key_pressed);
980
981 int err = audioproc_->ProcessStream(&_audioFrame);
982 if (err != 0) {
983 LOG(LS_ERROR) << "ProcessStream() error: " << err;
984 assert(false);
985 }
986
987 // Store new capture level. Only updated when analog AGC is enabled.
988 _captureLevel = agc->stream_analog_level();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000989}
990
henrik.lundinf00082d2016-12-05 02:22:12 -0800991#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000992void TransmitMixer::TypingDetection(bool keyPressed)
993{
994 // We let the VAD determine if we're using this feature or not.
995 if (_audioFrame.vad_activity_ == AudioFrame::kVadUnknown) {
996 return;
997 }
998
999 bool vadActive = _audioFrame.vad_activity_ == AudioFrame::kVadActive;
1000 if (_typingDetection.Process(keyPressed, vadActive)) {
tommi31fc21f2016-01-21 10:37:37 -08001001 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001002 _typingNoiseWarningPending = true;
1003 _typingNoiseDetected = true;
1004 } else {
tommi31fc21f2016-01-21 10:37:37 -08001005 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001006 // If there is already a warning pending, do not change the state.
1007 // Otherwise set a warning pending if last callback was for noise detected.
1008 if (!_typingNoiseWarningPending && _typingNoiseDetected) {
1009 _typingNoiseWarningPending = true;
1010 _typingNoiseDetected = false;
1011 }
1012 }
1013}
1014#endif
1015
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001016void TransmitMixer::EnableStereoChannelSwapping(bool enable) {
1017 swap_stereo_channels_ = enable;
1018}
1019
1020bool TransmitMixer::IsStereoChannelSwappingEnabled() {
1021 return swap_stereo_channels_;
1022}
1023
1024} // namespace voe
1025} // namespace webrtc