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