Home | History | Annotate | Download | only in voice_engine
      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/base/format_macros.h"
     14 #include "webrtc/base/logging.h"
     15 #include "webrtc/modules/utility/include/audio_frame_operations.h"
     16 #include "webrtc/system_wrappers/include/critical_section_wrapper.h"
     17 #include "webrtc/system_wrappers/include/event_wrapper.h"
     18 #include "webrtc/system_wrappers/include/trace.h"
     19 #include "webrtc/voice_engine/channel.h"
     20 #include "webrtc/voice_engine/channel_manager.h"
     21 #include "webrtc/voice_engine/include/voe_external_media.h"
     22 #include "webrtc/voice_engine/statistics.h"
     23 #include "webrtc/voice_engine/utility.h"
     24 #include "webrtc/voice_engine/voe_base_impl.h"
     25 
     26 namespace webrtc {
     27 namespace voe {
     28 
     29 // TODO(ajm): The thread safety of this is dubious...
     30 void
     31 TransmitMixer::OnPeriodicProcess()
     32 {
     33     WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
     34                  "TransmitMixer::OnPeriodicProcess()");
     35 
     36 #if defined(WEBRTC_VOICE_ENGINE_TYPING_DETECTION)
     37     bool send_typing_noise_warning = false;
     38     bool typing_noise_detected = false;
     39     {
     40       CriticalSectionScoped cs(&_critSect);
     41       if (_typingNoiseWarningPending) {
     42         send_typing_noise_warning = true;
     43         typing_noise_detected = _typingNoiseDetected;
     44         _typingNoiseWarningPending = false;
     45       }
     46     }
     47     if (send_typing_noise_warning) {
     48         CriticalSectionScoped cs(&_callbackCritSect);
     49         if (_voiceEngineObserverPtr) {
     50             if (typing_noise_detected) {
     51                 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
     52                              "TransmitMixer::OnPeriodicProcess() => "
     53                              "CallbackOnError(VE_TYPING_NOISE_WARNING)");
     54                 _voiceEngineObserverPtr->CallbackOnError(
     55                     -1,
     56                     VE_TYPING_NOISE_WARNING);
     57             } else {
     58                 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
     59                              "TransmitMixer::OnPeriodicProcess() => "
     60                              "CallbackOnError(VE_TYPING_NOISE_OFF_WARNING)");
     61                 _voiceEngineObserverPtr->CallbackOnError(
     62                     -1,
     63                     VE_TYPING_NOISE_OFF_WARNING);
     64             }
     65         }
     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     _processThreadPtr->RegisterModule(&_monitorModule);
    269     _monitorModule.RegisterObserver(*this);
    270 
    271     return 0;
    272 }
    273 
    274 int32_t
    275 TransmitMixer::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
    276 {
    277     WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
    278                  "TransmitMixer::RegisterVoiceEngineObserver()");
    279     CriticalSectionScoped cs(&_callbackCritSect);
    280 
    281     if (_voiceEngineObserverPtr)
    282     {
    283         _engineStatisticsPtr->SetLastError(
    284             VE_INVALID_OPERATION, kTraceError,
    285             "RegisterVoiceEngineObserver() observer already enabled");
    286         return -1;
    287     }
    288     _voiceEngineObserverPtr = &observer;
    289     return 0;
    290 }
    291 
    292 int32_t
    293 TransmitMixer::SetAudioProcessingModule(AudioProcessing* audioProcessingModule)
    294 {
    295     WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
    296                  "TransmitMixer::SetAudioProcessingModule("
    297                  "audioProcessingModule=0x%x)",
    298                  audioProcessingModule);
    299     audioproc_ = audioProcessingModule;
    300     return 0;
    301 }
    302 
    303 void TransmitMixer::GetSendCodecInfo(int* max_sample_rate,
    304                                      size_t* max_channels) {
    305   *max_sample_rate = 8000;
    306   *max_channels = 1;
    307   for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
    308        it.Increment()) {
    309     Channel* channel = it.GetChannel();
    310     if (channel->Sending()) {
    311       CodecInst codec;
    312       channel->GetSendCodec(codec);
    313       *max_sample_rate = std::max(*max_sample_rate, codec.plfreq);
    314       *max_channels = std::max(*max_channels, codec.channels);
    315     }
    316   }
    317 }
    318 
    319 int32_t
    320 TransmitMixer::PrepareDemux(const void* audioSamples,
    321                             size_t nSamples,
    322                             size_t nChannels,
    323                             uint32_t samplesPerSec,
    324                             uint16_t totalDelayMS,
    325                             int32_t clockDrift,
    326                             uint16_t currentMicLevel,
    327                             bool keyPressed)
    328 {
    329     WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
    330                  "TransmitMixer::PrepareDemux(nSamples=%" PRIuS ", "
    331                  "nChannels=%" PRIuS ", samplesPerSec=%u, totalDelayMS=%u, "
    332                  "clockDrift=%d, currentMicLevel=%u)",
    333                  nSamples, nChannels, samplesPerSec, totalDelayMS, clockDrift,
    334                  currentMicLevel);
    335 
    336     // --- Resample input audio and create/store the initial audio frame
    337     GenerateAudioFrame(static_cast<const int16_t*>(audioSamples),
    338                        nSamples,
    339                        nChannels,
    340                        samplesPerSec);
    341 
    342     {
    343       CriticalSectionScoped cs(&_callbackCritSect);
    344       if (external_preproc_ptr_) {
    345         external_preproc_ptr_->Process(-1, kRecordingPreprocessing,
    346                                        _audioFrame.data_,
    347                                        _audioFrame.samples_per_channel_,
    348                                        _audioFrame.sample_rate_hz_,
    349                                        _audioFrame.num_channels_ == 2);
    350       }
    351     }
    352 
    353     // --- Near-end audio processing.
    354     ProcessAudio(totalDelayMS, clockDrift, currentMicLevel, keyPressed);
    355 
    356     if (swap_stereo_channels_ && stereo_codec_)
    357       // Only bother swapping if we're using a stereo codec.
    358       AudioFrameOperations::SwapStereoChannels(&_audioFrame);
    359 
    360     // --- Annoying typing detection (utilizes the APM/VAD decision)
    361 #ifdef WEBRTC_VOICE_ENGINE_TYPING_DETECTION
    362     TypingDetection(keyPressed);
    363 #endif
    364 
    365     // --- Mute during DTMF tone if direct feedback is enabled
    366     if (_remainingMuteMicTimeMs > 0)
    367     {
    368         AudioFrameOperations::Mute(_audioFrame);
    369         _remainingMuteMicTimeMs -= 10;
    370         if (_remainingMuteMicTimeMs < 0)
    371         {
    372             _remainingMuteMicTimeMs = 0;
    373         }
    374     }
    375 
    376     // --- Mute signal
    377     if (_mute)
    378     {
    379         AudioFrameOperations::Mute(_audioFrame);
    380     }
    381 
    382     // --- Mix with file (does not affect the mixing frequency)
    383     if (_filePlaying)
    384     {
    385         MixOrReplaceAudioWithFile(_audioFrame.sample_rate_hz_);
    386     }
    387 
    388     // --- Record to file
    389     bool file_recording = false;
    390     {
    391         CriticalSectionScoped cs(&_critSect);
    392         file_recording =  _fileRecording;
    393     }
    394     if (file_recording)
    395     {
    396         RecordAudioToFile(_audioFrame.sample_rate_hz_);
    397     }
    398 
    399     {
    400       CriticalSectionScoped cs(&_callbackCritSect);
    401       if (external_postproc_ptr_) {
    402         external_postproc_ptr_->Process(-1, kRecordingAllChannelsMixed,
    403                                         _audioFrame.data_,
    404                                         _audioFrame.samples_per_channel_,
    405                                         _audioFrame.sample_rate_hz_,
    406                                         _audioFrame.num_channels_ == 2);
    407       }
    408     }
    409 
    410     // --- Measure audio level of speech after all processing.
    411     _audioLevel.ComputeLevel(_audioFrame);
    412     return 0;
    413 }
    414 
    415 int32_t
    416 TransmitMixer::DemuxAndMix()
    417 {
    418     WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
    419                  "TransmitMixer::DemuxAndMix()");
    420 
    421     for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
    422          it.Increment())
    423     {
    424         Channel* channelPtr = it.GetChannel();
    425         if (channelPtr->Sending())
    426         {
    427             // Demultiplex makes a copy of its input.
    428             channelPtr->Demultiplex(_audioFrame);
    429             channelPtr->PrepareEncodeAndSend(_audioFrame.sample_rate_hz_);
    430         }
    431     }
    432     return 0;
    433 }
    434 
    435 void TransmitMixer::DemuxAndMix(const int voe_channels[],
    436                                 size_t number_of_voe_channels) {
    437   for (size_t i = 0; i < number_of_voe_channels; ++i) {
    438     voe::ChannelOwner ch = _channelManagerPtr->GetChannel(voe_channels[i]);
    439     voe::Channel* channel_ptr = ch.channel();
    440     if (channel_ptr) {
    441       if (channel_ptr->Sending()) {
    442         // Demultiplex makes a copy of its input.
    443         channel_ptr->Demultiplex(_audioFrame);
    444         channel_ptr->PrepareEncodeAndSend(_audioFrame.sample_rate_hz_);
    445       }
    446     }
    447   }
    448 }
    449 
    450 int32_t
    451 TransmitMixer::EncodeAndSend()
    452 {
    453     WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
    454                  "TransmitMixer::EncodeAndSend()");
    455 
    456     for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
    457          it.Increment())
    458     {
    459         Channel* channelPtr = it.GetChannel();
    460         if (channelPtr->Sending())
    461         {
    462             channelPtr->EncodeAndSend();
    463         }
    464     }
    465     return 0;
    466 }
    467 
    468 void TransmitMixer::EncodeAndSend(const int voe_channels[],
    469                                   size_t number_of_voe_channels) {
    470   for (size_t i = 0; i < number_of_voe_channels; ++i) {
    471     voe::ChannelOwner ch = _channelManagerPtr->GetChannel(voe_channels[i]);
    472     voe::Channel* channel_ptr = ch.channel();
    473     if (channel_ptr && channel_ptr->Sending())
    474       channel_ptr->EncodeAndSend();
    475   }
    476 }
    477 
    478 uint32_t TransmitMixer::CaptureLevel() const
    479 {
    480     return _captureLevel;
    481 }
    482 
    483 void
    484 TransmitMixer::UpdateMuteMicrophoneTime(uint32_t lengthMs)
    485 {
    486     WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
    487                "TransmitMixer::UpdateMuteMicrophoneTime(lengthMs=%d)",
    488                lengthMs);
    489     _remainingMuteMicTimeMs = lengthMs;
    490 }
    491 
    492 int32_t
    493 TransmitMixer::StopSend()
    494 {
    495     WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
    496                "TransmitMixer::StopSend()");
    497     _audioLevel.Clear();
    498     return 0;
    499 }
    500 
    501 int TransmitMixer::StartPlayingFileAsMicrophone(const char* fileName,
    502                                                 bool loop,
    503                                                 FileFormats format,
    504                                                 int startPosition,
    505                                                 float volumeScaling,
    506                                                 int stopPosition,
    507                                                 const CodecInst* codecInst)
    508 {
    509     WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
    510                  "TransmitMixer::StartPlayingFileAsMicrophone("
    511                  "fileNameUTF8[]=%s,loop=%d, format=%d, volumeScaling=%5.3f,"
    512                  " startPosition=%d, stopPosition=%d)", fileName, loop,
    513                  format, volumeScaling, startPosition, stopPosition);
    514 
    515     if (_filePlaying)
    516     {
    517         _engineStatisticsPtr->SetLastError(
    518             VE_ALREADY_PLAYING, kTraceWarning,
    519             "StartPlayingFileAsMicrophone() is already playing");
    520         return 0;
    521     }
    522 
    523     CriticalSectionScoped cs(&_critSect);
    524 
    525     // Destroy the old instance
    526     if (_filePlayerPtr)
    527     {
    528         _filePlayerPtr->RegisterModuleFileCallback(NULL);
    529         FilePlayer::DestroyFilePlayer(_filePlayerPtr);
    530         _filePlayerPtr = NULL;
    531     }
    532 
    533     // Dynamically create the instance
    534     _filePlayerPtr
    535         = FilePlayer::CreateFilePlayer(_filePlayerId,
    536                                        (const FileFormats) format);
    537 
    538     if (_filePlayerPtr == NULL)
    539     {
    540         _engineStatisticsPtr->SetLastError(
    541             VE_INVALID_ARGUMENT, kTraceError,
    542             "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
    543         return -1;
    544     }
    545 
    546     const uint32_t notificationTime(0);
    547 
    548     if (_filePlayerPtr->StartPlayingFile(
    549         fileName,
    550         loop,
    551         startPosition,
    552         volumeScaling,
    553         notificationTime,
    554         stopPosition,
    555         (const CodecInst*) codecInst) != 0)
    556     {
    557         _engineStatisticsPtr->SetLastError(
    558             VE_BAD_FILE, kTraceError,
    559             "StartPlayingFile() failed to start file playout");
    560         _filePlayerPtr->StopPlayingFile();
    561         FilePlayer::DestroyFilePlayer(_filePlayerPtr);
    562         _filePlayerPtr = NULL;
    563         return -1;
    564     }
    565 
    566     _filePlayerPtr->RegisterModuleFileCallback(this);
    567     _filePlaying = true;
    568 
    569     return 0;
    570 }
    571 
    572 int TransmitMixer::StartPlayingFileAsMicrophone(InStream* stream,
    573                                                 FileFormats format,
    574                                                 int startPosition,
    575                                                 float volumeScaling,
    576                                                 int stopPosition,
    577                                                 const CodecInst* codecInst)
    578 {
    579     WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
    580                  "TransmitMixer::StartPlayingFileAsMicrophone(format=%d,"
    581                  " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
    582                  format, volumeScaling, startPosition, stopPosition);
    583 
    584     if (stream == NULL)
    585     {
    586         _engineStatisticsPtr->SetLastError(
    587             VE_BAD_FILE, kTraceError,
    588             "StartPlayingFileAsMicrophone() NULL as input stream");
    589         return -1;
    590     }
    591 
    592     if (_filePlaying)
    593     {
    594         _engineStatisticsPtr->SetLastError(
    595             VE_ALREADY_PLAYING, kTraceWarning,
    596             "StartPlayingFileAsMicrophone() is already playing");
    597         return 0;
    598     }
    599 
    600     CriticalSectionScoped cs(&_critSect);
    601 
    602     // Destroy the old instance
    603     if (_filePlayerPtr)
    604     {
    605         _filePlayerPtr->RegisterModuleFileCallback(NULL);
    606         FilePlayer::DestroyFilePlayer(_filePlayerPtr);
    607         _filePlayerPtr = NULL;
    608     }
    609 
    610     // Dynamically create the instance
    611     _filePlayerPtr
    612         = FilePlayer::CreateFilePlayer(_filePlayerId,
    613                                        (const FileFormats) format);
    614 
    615     if (_filePlayerPtr == NULL)
    616     {
    617         _engineStatisticsPtr->SetLastError(
    618             VE_INVALID_ARGUMENT, kTraceWarning,
    619             "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
    620         return -1;
    621     }
    622 
    623     const uint32_t notificationTime(0);
    624 
    625     if (_filePlayerPtr->StartPlayingFile(
    626         (InStream&) *stream,
    627         startPosition,
    628         volumeScaling,
    629         notificationTime,
    630         stopPosition,
    631         (const CodecInst*) codecInst) != 0)
    632     {
    633         _engineStatisticsPtr->SetLastError(
    634             VE_BAD_FILE, kTraceError,
    635             "StartPlayingFile() failed to start file playout");
    636         _filePlayerPtr->StopPlayingFile();
    637         FilePlayer::DestroyFilePlayer(_filePlayerPtr);
    638         _filePlayerPtr = NULL;
    639         return -1;
    640     }
    641     _filePlayerPtr->RegisterModuleFileCallback(this);
    642     _filePlaying = true;
    643 
    644     return 0;
    645 }
    646 
    647 int TransmitMixer::StopPlayingFileAsMicrophone()
    648 {
    649     WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
    650                  "TransmitMixer::StopPlayingFileAsMicrophone()");
    651 
    652     if (!_filePlaying)
    653     {
    654         return 0;
    655     }
    656 
    657     CriticalSectionScoped cs(&_critSect);
    658 
    659     if (_filePlayerPtr->StopPlayingFile() != 0)
    660     {
    661         _engineStatisticsPtr->SetLastError(
    662             VE_CANNOT_STOP_PLAYOUT, kTraceError,
    663             "StopPlayingFile() couldnot stop playing file");
    664         return -1;
    665     }
    666 
    667     _filePlayerPtr->RegisterModuleFileCallback(NULL);
    668     FilePlayer::DestroyFilePlayer(_filePlayerPtr);
    669     _filePlayerPtr = NULL;
    670     _filePlaying = false;
    671 
    672     return 0;
    673 }
    674 
    675 int TransmitMixer::IsPlayingFileAsMicrophone() const
    676 {
    677     WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
    678                  "TransmitMixer::IsPlayingFileAsMicrophone()");
    679     return _filePlaying;
    680 }
    681 
    682 int TransmitMixer::StartRecordingMicrophone(const char* fileName,
    683                                             const CodecInst* codecInst)
    684 {
    685     WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
    686                  "TransmitMixer::StartRecordingMicrophone(fileName=%s)",
    687                  fileName);
    688 
    689     CriticalSectionScoped cs(&_critSect);
    690 
    691     if (_fileRecording)
    692     {
    693         WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
    694                      "StartRecordingMicrophone() is already recording");
    695         return 0;
    696     }
    697 
    698     FileFormats format;
    699     const uint32_t notificationTime(0); // Not supported in VoE
    700     CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
    701 
    702     if (codecInst != NULL && codecInst->channels > 2)
    703     {
    704         _engineStatisticsPtr->SetLastError(
    705             VE_BAD_ARGUMENT, kTraceError,
    706             "StartRecordingMicrophone() invalid compression");
    707         return (-1);
    708     }
    709     if (codecInst == NULL)
    710     {
    711         format = kFileFormatPcm16kHzFile;
    712         codecInst = &dummyCodec;
    713     } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
    714         (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
    715         (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
    716     {
    717         format = kFileFormatWavFile;
    718     } else
    719     {
    720         format = kFileFormatCompressedFile;
    721     }
    722 
    723     // Destroy the old instance
    724     if (_fileRecorderPtr)
    725     {
    726         _fileRecorderPtr->RegisterModuleFileCallback(NULL);
    727         FileRecorder::DestroyFileRecorder(_fileRecorderPtr);
    728         _fileRecorderPtr = NULL;
    729     }
    730 
    731     _fileRecorderPtr =
    732         FileRecorder::CreateFileRecorder(_fileRecorderId,
    733                                          (const FileFormats) format);
    734     if (_fileRecorderPtr == NULL)
    735     {
    736         _engineStatisticsPtr->SetLastError(
    737             VE_INVALID_ARGUMENT, kTraceError,
    738             "StartRecordingMicrophone() fileRecorder format isnot correct");
    739         return -1;
    740     }
    741 
    742     if (_fileRecorderPtr->StartRecordingAudioFile(
    743         fileName,
    744         (const CodecInst&) *codecInst,
    745         notificationTime) != 0)
    746     {
    747         _engineStatisticsPtr->SetLastError(
    748             VE_BAD_FILE, kTraceError,
    749             "StartRecordingAudioFile() failed to start file recording");
    750         _fileRecorderPtr->StopRecording();
    751         FileRecorder::DestroyFileRecorder(_fileRecorderPtr);
    752         _fileRecorderPtr = NULL;
    753         return -1;
    754     }
    755     _fileRecorderPtr->RegisterModuleFileCallback(this);
    756     _fileRecording = true;
    757 
    758     return 0;
    759 }
    760 
    761 int TransmitMixer::StartRecordingMicrophone(OutStream* stream,
    762                                             const CodecInst* codecInst)
    763 {
    764     WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
    765                "TransmitMixer::StartRecordingMicrophone()");
    766 
    767     CriticalSectionScoped cs(&_critSect);
    768 
    769     if (_fileRecording)
    770     {
    771         WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
    772                    "StartRecordingMicrophone() is already recording");
    773         return 0;
    774     }
    775 
    776     FileFormats format;
    777     const uint32_t notificationTime(0); // Not supported in VoE
    778     CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
    779 
    780     if (codecInst != NULL && codecInst->channels != 1)
    781     {
    782         _engineStatisticsPtr->SetLastError(
    783             VE_BAD_ARGUMENT, kTraceError,
    784             "StartRecordingMicrophone() invalid compression");
    785         return (-1);
    786     }
    787     if (codecInst == NULL)
    788     {
    789         format = kFileFormatPcm16kHzFile;
    790         codecInst = &dummyCodec;
    791     } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
    792         (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
    793         (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
    794     {
    795         format = kFileFormatWavFile;
    796     } else
    797     {
    798         format = kFileFormatCompressedFile;
    799     }
    800 
    801     // Destroy the old instance
    802     if (_fileRecorderPtr)
    803     {
    804         _fileRecorderPtr->RegisterModuleFileCallback(NULL);
    805         FileRecorder::DestroyFileRecorder(_fileRecorderPtr);
    806         _fileRecorderPtr = NULL;
    807     }
    808 
    809     _fileRecorderPtr =
    810         FileRecorder::CreateFileRecorder(_fileRecorderId,
    811                                          (const FileFormats) format);
    812     if (_fileRecorderPtr == NULL)
    813     {
    814         _engineStatisticsPtr->SetLastError(
    815             VE_INVALID_ARGUMENT, kTraceError,
    816             "StartRecordingMicrophone() fileRecorder format isnot correct");
    817         return -1;
    818     }
    819 
    820     if (_fileRecorderPtr->StartRecordingAudioFile(*stream,
    821                                                   *codecInst,
    822                                                   notificationTime) != 0)
    823     {
    824     _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
    825       "StartRecordingAudioFile() failed to start file recording");
    826     _fileRecorderPtr->StopRecording();
    827     FileRecorder::DestroyFileRecorder(_fileRecorderPtr);
    828     _fileRecorderPtr = NULL;
    829     return -1;
    830     }
    831 
    832     _fileRecorderPtr->RegisterModuleFileCallback(this);
    833     _fileRecording = true;
    834 
    835     return 0;
    836 }
    837 
    838 
    839 int TransmitMixer::StopRecordingMicrophone()
    840 {
    841     WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
    842                  "TransmitMixer::StopRecordingMicrophone()");
    843 
    844     CriticalSectionScoped cs(&_critSect);
    845 
    846     if (!_fileRecording)
    847     {
    848         WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
    849                    "StopRecordingMicrophone() isnot recording");
    850         return 0;
    851     }
    852 
    853     if (_fileRecorderPtr->StopRecording() != 0)
    854     {
    855         _engineStatisticsPtr->SetLastError(
    856             VE_STOP_RECORDING_FAILED, kTraceError,
    857             "StopRecording(), could not stop recording");
    858         return -1;
    859     }
    860     _fileRecorderPtr->RegisterModuleFileCallback(NULL);
    861     FileRecorder::DestroyFileRecorder(_fileRecorderPtr);
    862     _fileRecorderPtr = NULL;
    863     _fileRecording = false;
    864 
    865     return 0;
    866 }
    867 
    868 int TransmitMixer::StartRecordingCall(const char* fileName,
    869                                       const CodecInst* codecInst)
    870 {
    871     WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
    872                  "TransmitMixer::StartRecordingCall(fileName=%s)", fileName);
    873 
    874     if (_fileCallRecording)
    875     {
    876         WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
    877                      "StartRecordingCall() is already recording");
    878         return 0;
    879     }
    880 
    881     FileFormats format;
    882     const uint32_t notificationTime(0); // Not supported in VoE
    883     CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
    884 
    885     if (codecInst != NULL && codecInst->channels != 1)
    886     {
    887         _engineStatisticsPtr->SetLastError(
    888             VE_BAD_ARGUMENT, kTraceError,
    889             "StartRecordingCall() invalid compression");
    890         return (-1);
    891     }
    892     if (codecInst == NULL)
    893     {
    894         format = kFileFormatPcm16kHzFile;
    895         codecInst = &dummyCodec;
    896     } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
    897         (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
    898         (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
    899     {
    900         format = kFileFormatWavFile;
    901     } else
    902     {
    903         format = kFileFormatCompressedFile;
    904     }
    905 
    906     CriticalSectionScoped cs(&_critSect);
    907 
    908     // Destroy the old instance
    909     if (_fileCallRecorderPtr)
    910     {
    911         _fileCallRecorderPtr->RegisterModuleFileCallback(NULL);
    912         FileRecorder::DestroyFileRecorder(_fileCallRecorderPtr);
    913         _fileCallRecorderPtr = NULL;
    914     }
    915 
    916     _fileCallRecorderPtr
    917         = FileRecorder::CreateFileRecorder(_fileCallRecorderId,
    918                                            (const FileFormats) format);
    919     if (_fileCallRecorderPtr == NULL)
    920     {
    921         _engineStatisticsPtr->SetLastError(
    922             VE_INVALID_ARGUMENT, kTraceError,
    923             "StartRecordingCall() fileRecorder format isnot correct");
    924         return -1;
    925     }
    926 
    927     if (_fileCallRecorderPtr->StartRecordingAudioFile(
    928         fileName,
    929         (const CodecInst&) *codecInst,
    930         notificationTime) != 0)
    931     {
    932         _engineStatisticsPtr->SetLastError(
    933             VE_BAD_FILE, kTraceError,
    934             "StartRecordingAudioFile() failed to start file recording");
    935         _fileCallRecorderPtr->StopRecording();
    936         FileRecorder::DestroyFileRecorder(_fileCallRecorderPtr);
    937         _fileCallRecorderPtr = NULL;
    938         return -1;
    939     }
    940     _fileCallRecorderPtr->RegisterModuleFileCallback(this);
    941     _fileCallRecording = true;
    942 
    943     return 0;
    944 }
    945 
    946 int TransmitMixer::StartRecordingCall(OutStream* stream,
    947                                       const  CodecInst* codecInst)
    948 {
    949     WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
    950                  "TransmitMixer::StartRecordingCall()");
    951 
    952     if (_fileCallRecording)
    953     {
    954         WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
    955                      "StartRecordingCall() is already recording");
    956         return 0;
    957     }
    958 
    959     FileFormats format;
    960     const uint32_t notificationTime(0); // Not supported in VoE
    961     CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
    962 
    963     if (codecInst != NULL && codecInst->channels != 1)
    964     {
    965         _engineStatisticsPtr->SetLastError(
    966             VE_BAD_ARGUMENT, kTraceError,
    967             "StartRecordingCall() invalid compression");
    968         return (-1);
    969     }
    970     if (codecInst == NULL)
    971     {
    972         format = kFileFormatPcm16kHzFile;
    973         codecInst = &dummyCodec;
    974     } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
    975         (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
    976         (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
    977     {
    978         format = kFileFormatWavFile;
    979     } else
    980     {
    981         format = kFileFormatCompressedFile;
    982     }
    983 
    984     CriticalSectionScoped cs(&_critSect);
    985 
    986     // Destroy the old instance
    987     if (_fileCallRecorderPtr)
    988     {
    989         _fileCallRecorderPtr->RegisterModuleFileCallback(NULL);
    990         FileRecorder::DestroyFileRecorder(_fileCallRecorderPtr);
    991         _fileCallRecorderPtr = NULL;
    992     }
    993 
    994     _fileCallRecorderPtr =
    995         FileRecorder::CreateFileRecorder(_fileCallRecorderId,
    996                                          (const FileFormats) format);
    997     if (_fileCallRecorderPtr == NULL)
    998     {
    999         _engineStatisticsPtr->SetLastError(
   1000             VE_INVALID_ARGUMENT, kTraceError,
   1001             "StartRecordingCall() fileRecorder format isnot correct");
   1002         return -1;
   1003     }
   1004 
   1005     if (_fileCallRecorderPtr->StartRecordingAudioFile(*stream,
   1006                                                       *codecInst,
   1007                                                       notificationTime) != 0)
   1008     {
   1009     _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
   1010      "StartRecordingAudioFile() failed to start file recording");
   1011     _fileCallRecorderPtr->StopRecording();
   1012     FileRecorder::DestroyFileRecorder(_fileCallRecorderPtr);
   1013     _fileCallRecorderPtr = NULL;
   1014     return -1;
   1015     }
   1016 
   1017     _fileCallRecorderPtr->RegisterModuleFileCallback(this);
   1018     _fileCallRecording = true;
   1019 
   1020     return 0;
   1021 }
   1022 
   1023 int TransmitMixer::StopRecordingCall()
   1024 {
   1025     WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
   1026                  "TransmitMixer::StopRecordingCall()");
   1027 
   1028     if (!_fileCallRecording)
   1029     {
   1030         WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
   1031                      "StopRecordingCall() file isnot recording");
   1032         return -1;
   1033     }
   1034 
   1035     CriticalSectionScoped cs(&_critSect);
   1036 
   1037     if (_fileCallRecorderPtr->StopRecording() != 0)
   1038     {
   1039         _engineStatisticsPtr->SetLastError(
   1040             VE_STOP_RECORDING_FAILED, kTraceError,
   1041             "StopRecording(), could not stop recording");
   1042         return -1;
   1043     }
   1044 
   1045     _fileCallRecorderPtr->RegisterModuleFileCallback(NULL);
   1046     FileRecorder::DestroyFileRecorder(_fileCallRecorderPtr);
   1047     _fileCallRecorderPtr = NULL;
   1048     _fileCallRecording = false;
   1049 
   1050     return 0;
   1051 }
   1052 
   1053 void
   1054 TransmitMixer::SetMixWithMicStatus(bool mix)
   1055 {
   1056     _mixFileWithMicrophone = mix;
   1057 }
   1058 
   1059 int TransmitMixer::RegisterExternalMediaProcessing(
   1060     VoEMediaProcess* object,
   1061     ProcessingTypes type) {
   1062   WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
   1063                "TransmitMixer::RegisterExternalMediaProcessing()");
   1064 
   1065   CriticalSectionScoped cs(&_callbackCritSect);
   1066   if (!object) {
   1067     return -1;
   1068   }
   1069 
   1070   // Store the callback object according to the processing type.
   1071   if (type == kRecordingAllChannelsMixed) {
   1072     external_postproc_ptr_ = object;
   1073   } else if (type == kRecordingPreprocessing) {
   1074     external_preproc_ptr_ = object;
   1075   } else {
   1076     return -1;
   1077   }
   1078   return 0;
   1079 }
   1080 
   1081 int TransmitMixer::DeRegisterExternalMediaProcessing(ProcessingTypes type) {
   1082   WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
   1083                "TransmitMixer::DeRegisterExternalMediaProcessing()");
   1084 
   1085   CriticalSectionScoped cs(&_callbackCritSect);
   1086   if (type == kRecordingAllChannelsMixed) {
   1087     external_postproc_ptr_ = NULL;
   1088   } else if (type == kRecordingPreprocessing) {
   1089     external_preproc_ptr_ = NULL;
   1090   } else {
   1091     return -1;
   1092   }
   1093   return 0;
   1094 }
   1095 
   1096 int
   1097 TransmitMixer::SetMute(bool enable)
   1098 {
   1099     WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
   1100                  "TransmitMixer::SetMute(enable=%d)", enable);
   1101     _mute = enable;
   1102     return 0;
   1103 }
   1104 
   1105 bool
   1106 TransmitMixer::Mute() const
   1107 {
   1108     return _mute;
   1109 }
   1110 
   1111 int8_t TransmitMixer::AudioLevel() const
   1112 {
   1113     // Speech + file level [0,9]
   1114     return _audioLevel.Level();
   1115 }
   1116 
   1117 int16_t TransmitMixer::AudioLevelFullRange() const
   1118 {
   1119     // Speech + file level [0,32767]
   1120     return _audioLevel.LevelFullRange();
   1121 }
   1122 
   1123 bool TransmitMixer::IsRecordingCall()
   1124 {
   1125     return _fileCallRecording;
   1126 }
   1127 
   1128 bool TransmitMixer::IsRecordingMic()
   1129 {
   1130     CriticalSectionScoped cs(&_critSect);
   1131     return _fileRecording;
   1132 }
   1133 
   1134 void TransmitMixer::GenerateAudioFrame(const int16_t* audio,
   1135                                        size_t samples_per_channel,
   1136                                        size_t num_channels,
   1137                                        int sample_rate_hz) {
   1138   int codec_rate;
   1139   size_t num_codec_channels;
   1140   GetSendCodecInfo(&codec_rate, &num_codec_channels);
   1141   stereo_codec_ = num_codec_channels == 2;
   1142 
   1143   // We want to process at the lowest rate possible without losing information.
   1144   // Choose the lowest native rate at least equal to the input and codec rates.
   1145   const int min_processing_rate = std::min(sample_rate_hz, codec_rate);
   1146   for (size_t i = 0; i < AudioProcessing::kNumNativeSampleRates; ++i) {
   1147     _audioFrame.sample_rate_hz_ = AudioProcessing::kNativeSampleRatesHz[i];
   1148     if (_audioFrame.sample_rate_hz_ >= min_processing_rate) {
   1149       break;
   1150     }
   1151   }
   1152   if (audioproc_->echo_control_mobile()->is_enabled()) {
   1153     // AECM only supports 8 and 16 kHz.
   1154     _audioFrame.sample_rate_hz_ = std::min(
   1155         _audioFrame.sample_rate_hz_, AudioProcessing::kMaxAECMSampleRateHz);
   1156   }
   1157   _audioFrame.num_channels_ = std::min(num_channels, num_codec_channels);
   1158   RemixAndResample(audio, samples_per_channel, num_channels, sample_rate_hz,
   1159                    &resampler_, &_audioFrame);
   1160 }
   1161 
   1162 int32_t TransmitMixer::RecordAudioToFile(
   1163     uint32_t mixingFrequency)
   1164 {
   1165     CriticalSectionScoped cs(&_critSect);
   1166     if (_fileRecorderPtr == NULL)
   1167     {
   1168         WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
   1169                      "TransmitMixer::RecordAudioToFile() filerecorder doesnot"
   1170                      "exist");
   1171         return -1;
   1172     }
   1173 
   1174     if (_fileRecorderPtr->RecordAudioToFile(_audioFrame) != 0)
   1175     {
   1176         WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
   1177                      "TransmitMixer::RecordAudioToFile() file recording"
   1178                      "failed");
   1179         return -1;
   1180     }
   1181 
   1182     return 0;
   1183 }
   1184 
   1185 int32_t TransmitMixer::MixOrReplaceAudioWithFile(
   1186     int mixingFrequency)
   1187 {
   1188   rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
   1189 
   1190     size_t fileSamples(0);
   1191     {
   1192         CriticalSectionScoped cs(&_critSect);
   1193         if (_filePlayerPtr == NULL)
   1194         {
   1195             WEBRTC_TRACE(kTraceWarning, kTraceVoice,
   1196                          VoEId(_instanceId, -1),
   1197                          "TransmitMixer::MixOrReplaceAudioWithFile()"
   1198                          "fileplayer doesnot exist");
   1199             return -1;
   1200         }
   1201 
   1202         if (_filePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
   1203                                                  fileSamples,
   1204                                                  mixingFrequency) == -1)
   1205         {
   1206             WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
   1207                          "TransmitMixer::MixOrReplaceAudioWithFile() file"
   1208                          " mixing failed");
   1209             return -1;
   1210         }
   1211     }
   1212 
   1213     assert(_audioFrame.samples_per_channel_ == fileSamples);
   1214 
   1215     if (_mixFileWithMicrophone)
   1216     {
   1217         // Currently file stream is always mono.
   1218         // TODO(xians): Change the code when FilePlayer supports real stereo.
   1219         MixWithSat(_audioFrame.data_,
   1220                    _audioFrame.num_channels_,
   1221                    fileBuffer.get(),
   1222                    1,
   1223                    fileSamples);
   1224     } else
   1225     {
   1226         // Replace ACM audio with file.
   1227         // Currently file stream is always mono.
   1228         // TODO(xians): Change the code when FilePlayer supports real stereo.
   1229         _audioFrame.UpdateFrame(-1,
   1230                                 0xFFFFFFFF,
   1231                                 fileBuffer.get(),
   1232                                 fileSamples,
   1233                                 mixingFrequency,
   1234                                 AudioFrame::kNormalSpeech,
   1235                                 AudioFrame::kVadUnknown,
   1236                                 1);
   1237     }
   1238     return 0;
   1239 }
   1240 
   1241 void TransmitMixer::ProcessAudio(int delay_ms, int clock_drift,
   1242                                  int current_mic_level, bool key_pressed) {
   1243   if (audioproc_->set_stream_delay_ms(delay_ms) != 0) {
   1244     // Silently ignore this failure to avoid flooding the logs.
   1245   }
   1246 
   1247   GainControl* agc = audioproc_->gain_control();
   1248   if (agc->set_stream_analog_level(current_mic_level) != 0) {
   1249     LOG(LS_ERROR) << "set_stream_analog_level failed: current_mic_level = "
   1250                   << current_mic_level;
   1251     assert(false);
   1252   }
   1253 
   1254   EchoCancellation* aec = audioproc_->echo_cancellation();
   1255   if (aec->is_drift_compensation_enabled()) {
   1256     aec->set_stream_drift_samples(clock_drift);
   1257   }
   1258 
   1259   audioproc_->set_stream_key_pressed(key_pressed);
   1260 
   1261   int err = audioproc_->ProcessStream(&_audioFrame);
   1262   if (err != 0) {
   1263     LOG(LS_ERROR) << "ProcessStream() error: " << err;
   1264     assert(false);
   1265   }
   1266 
   1267   // Store new capture level. Only updated when analog AGC is enabled.
   1268   _captureLevel = agc->stream_analog_level();
   1269 
   1270   CriticalSectionScoped cs(&_critSect);
   1271   // Triggers a callback in OnPeriodicProcess().
   1272   _saturationWarning |= agc->stream_is_saturated();
   1273 }
   1274 
   1275 #ifdef WEBRTC_VOICE_ENGINE_TYPING_DETECTION
   1276 void TransmitMixer::TypingDetection(bool keyPressed)
   1277 {
   1278   // We let the VAD determine if we're using this feature or not.
   1279   if (_audioFrame.vad_activity_ == AudioFrame::kVadUnknown) {
   1280     return;
   1281   }
   1282 
   1283   bool vadActive = _audioFrame.vad_activity_ == AudioFrame::kVadActive;
   1284   if (_typingDetection.Process(keyPressed, vadActive)) {
   1285     CriticalSectionScoped cs(&_critSect);
   1286     _typingNoiseWarningPending = true;
   1287     _typingNoiseDetected = true;
   1288   } else {
   1289     CriticalSectionScoped cs(&_critSect);
   1290     // If there is already a warning pending, do not change the state.
   1291     // Otherwise set a warning pending if last callback was for noise detected.
   1292     if (!_typingNoiseWarningPending && _typingNoiseDetected) {
   1293       _typingNoiseWarningPending = true;
   1294       _typingNoiseDetected = false;
   1295     }
   1296   }
   1297 }
   1298 #endif
   1299 
   1300 int TransmitMixer::GetMixingFrequency()
   1301 {
   1302     assert(_audioFrame.sample_rate_hz_ != 0);
   1303     return _audioFrame.sample_rate_hz_;
   1304 }
   1305 
   1306 #ifdef WEBRTC_VOICE_ENGINE_TYPING_DETECTION
   1307 int TransmitMixer::TimeSinceLastTyping(int &seconds)
   1308 {
   1309     // We check in VoEAudioProcessingImpl that this is only called when
   1310     // typing detection is active.
   1311     seconds = _typingDetection.TimeSinceLastDetectionInSeconds();
   1312     return 0;
   1313 }
   1314 #endif
   1315 
   1316 #ifdef WEBRTC_VOICE_ENGINE_TYPING_DETECTION
   1317 int TransmitMixer::SetTypingDetectionParameters(int timeWindow,
   1318                                                 int costPerTyping,
   1319                                                 int reportingThreshold,
   1320                                                 int penaltyDecay,
   1321                                                 int typeEventDelay)
   1322 {
   1323     _typingDetection.SetParameters(timeWindow,
   1324                                    costPerTyping,
   1325                                    reportingThreshold,
   1326                                    penaltyDecay,
   1327                                    typeEventDelay,
   1328                                    0);
   1329     return 0;
   1330 }
   1331 #endif
   1332 
   1333 void TransmitMixer::EnableStereoChannelSwapping(bool enable) {
   1334   swap_stereo_channels_ = enable;
   1335 }
   1336 
   1337 bool TransmitMixer::IsStereoChannelSwappingEnabled() {
   1338   return swap_stereo_channels_;
   1339 }
   1340 
   1341 }  // namespace voe
   1342 }  // namespace webrtc
   1343