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