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