blob: ae9f0f90341d45975af2f7afbe72c9e917f27a3a [file] [log] [blame]
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001/*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/voice_engine/transmit_mixer.h"
12
kwibergb7f89d62016-02-17 10:04:18 -080013#include <memory>
14
aleloi6321b492016-12-05 01:46:09 -080015#include "webrtc/audio/utility/audio_frame_operations.h"
Peter Kastingdce40cf2015-08-24 14:52:23 -070016#include "webrtc/base/format_macros.h"
pbosad856222015-11-27 09:48:36 -080017#include "webrtc/base/logging.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010018#include "webrtc/system_wrappers/include/event_wrapper.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010019#include "webrtc/system_wrappers/include/trace.h"
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000020#include "webrtc/voice_engine/channel.h"
21#include "webrtc/voice_engine/channel_manager.h"
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000022#include "webrtc/voice_engine/statistics.h"
23#include "webrtc/voice_engine/utility.h"
24#include "webrtc/voice_engine/voe_base_impl.h"
25
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000026namespace webrtc {
27namespace voe {
28
tommiba08a142017-02-28 08:25:11 -080029#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000030// TODO(ajm): The thread safety of this is dubious...
tommiba08a142017-02-28 08:25:11 -080031void TransmitMixer::OnPeriodicProcess()
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000032{
33 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
34 "TransmitMixer::OnPeriodicProcess()");
35
solenberg302c9782015-11-24 06:28:22 -080036 bool send_typing_noise_warning = false;
37 bool typing_noise_detected = false;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000038 {
tommi31fc21f2016-01-21 10:37:37 -080039 rtc::CritScope cs(&_critSect);
solenberg302c9782015-11-24 06:28:22 -080040 if (_typingNoiseWarningPending) {
41 send_typing_noise_warning = true;
42 typing_noise_detected = _typingNoiseDetected;
43 _typingNoiseWarningPending = false;
44 }
45 }
46 if (send_typing_noise_warning) {
tommi31fc21f2016-01-21 10:37:37 -080047 rtc::CritScope cs(&_callbackCritSect);
solenberg302c9782015-11-24 06:28:22 -080048 if (_voiceEngineObserverPtr) {
49 if (typing_noise_detected) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000050 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
51 "TransmitMixer::OnPeriodicProcess() => "
52 "CallbackOnError(VE_TYPING_NOISE_WARNING)");
53 _voiceEngineObserverPtr->CallbackOnError(
54 -1,
55 VE_TYPING_NOISE_WARNING);
56 } else {
57 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
58 "TransmitMixer::OnPeriodicProcess() => "
59 "CallbackOnError(VE_TYPING_NOISE_OFF_WARNING)");
60 _voiceEngineObserverPtr->CallbackOnError(
61 -1,
62 VE_TYPING_NOISE_OFF_WARNING);
63 }
64 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000065 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000066}
tommiba08a142017-02-28 08:25:11 -080067#endif // WEBRTC_VOICE_ENGINE_TYPING_DETECTION
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000068
69void TransmitMixer::PlayNotification(int32_t id,
70 uint32_t durationMs)
71{
72 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
73 "TransmitMixer::PlayNotification(id=%d, durationMs=%d)",
74 id, durationMs);
75
76 // Not implement yet
77}
78
79void TransmitMixer::RecordNotification(int32_t id,
80 uint32_t durationMs)
81{
82 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1),
83 "TransmitMixer::RecordNotification(id=%d, durationMs=%d)",
84 id, durationMs);
85
86 // Not implement yet
87}
88
89void TransmitMixer::PlayFileEnded(int32_t id)
90{
91 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
92 "TransmitMixer::PlayFileEnded(id=%d)", id);
93
94 assert(id == _filePlayerId);
95
tommi31fc21f2016-01-21 10:37:37 -080096 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000097
98 _filePlaying = false;
99 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1),
100 "TransmitMixer::PlayFileEnded() =>"
101 "file player module is shutdown");
102}
103
104void
105TransmitMixer::RecordFileEnded(int32_t id)
106{
107 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
108 "TransmitMixer::RecordFileEnded(id=%d)", id);
109
110 if (id == _fileRecorderId)
111 {
tommi31fc21f2016-01-21 10:37:37 -0800112 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000113 _fileRecording = false;
114 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1),
115 "TransmitMixer::RecordFileEnded() => fileRecorder module"
116 "is shutdown");
117 } else if (id == _fileCallRecorderId)
118 {
tommi31fc21f2016-01-21 10:37:37 -0800119 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000120 _fileCallRecording = false;
121 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1),
122 "TransmitMixer::RecordFileEnded() => fileCallRecorder"
123 "module is shutdown");
124 }
125}
126
127int32_t
128TransmitMixer::Create(TransmitMixer*& mixer, uint32_t instanceId)
129{
130 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, -1),
131 "TransmitMixer::Create(instanceId=%d)", instanceId);
132 mixer = new TransmitMixer(instanceId);
133 if (mixer == NULL)
134 {
135 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, -1),
136 "TransmitMixer::Create() unable to allocate memory"
137 "for mixer");
138 return -1;
139 }
140 return 0;
141}
142
143void
144TransmitMixer::Destroy(TransmitMixer*& mixer)
145{
146 if (mixer)
147 {
148 delete mixer;
149 mixer = NULL;
150 }
151}
152
153TransmitMixer::TransmitMixer(uint32_t instanceId) :
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000154 // Avoid conflict with other channels by adding 1024 - 1026,
155 // won't use as much as 1024 channels.
156 _filePlayerId(instanceId + 1024),
157 _fileRecorderId(instanceId + 1025),
158 _fileCallRecorderId(instanceId + 1026),
tommiba08a142017-02-28 08:25:11 -0800159#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
160 _monitorModule(this),
161#endif
solenberg76377c52017-02-21 00:54:31 -0800162 _instanceId(instanceId)
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000163{
164 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1),
165 "TransmitMixer::TransmitMixer() - ctor");
166}
167
168TransmitMixer::~TransmitMixer()
169{
170 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1),
171 "TransmitMixer::~TransmitMixer() - dtor");
tommiba08a142017-02-28 08:25:11 -0800172#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000173 if (_processThreadPtr)
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000174 _processThreadPtr->DeRegisterModule(&_monitorModule);
tommiba08a142017-02-28 08:25:11 -0800175#endif
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000176 {
tommi31fc21f2016-01-21 10:37:37 -0800177 rtc::CritScope cs(&_critSect);
kwiberg5a25d952016-08-17 07:31:12 -0700178 if (file_recorder_) {
179 file_recorder_->RegisterModuleFileCallback(NULL);
180 file_recorder_->StopRecording();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000181 }
kwiberg5a25d952016-08-17 07:31:12 -0700182 if (file_call_recorder_) {
183 file_call_recorder_->RegisterModuleFileCallback(NULL);
184 file_call_recorder_->StopRecording();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000185 }
kwiberg5a25d952016-08-17 07:31:12 -0700186 if (file_player_) {
187 file_player_->RegisterModuleFileCallback(NULL);
188 file_player_->StopPlayingFile();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000189 }
190 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000191}
192
193int32_t
194TransmitMixer::SetEngineInformation(ProcessThread& processThread,
195 Statistics& engineStatistics,
196 ChannelManager& channelManager)
197{
198 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
199 "TransmitMixer::SetEngineInformation()");
200
201 _processThreadPtr = &processThread;
202 _engineStatisticsPtr = &engineStatistics;
203 _channelManagerPtr = &channelManager;
204
tommiba08a142017-02-28 08:25:11 -0800205#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000206 _processThreadPtr->RegisterModule(&_monitorModule);
tommiba08a142017-02-28 08:25:11 -0800207#endif
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000208 return 0;
209}
210
211int32_t
212TransmitMixer::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
213{
214 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
215 "TransmitMixer::RegisterVoiceEngineObserver()");
tommi31fc21f2016-01-21 10:37:37 -0800216 rtc::CritScope cs(&_callbackCritSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000217
218 if (_voiceEngineObserverPtr)
219 {
220 _engineStatisticsPtr->SetLastError(
221 VE_INVALID_OPERATION, kTraceError,
222 "RegisterVoiceEngineObserver() observer already enabled");
223 return -1;
224 }
225 _voiceEngineObserverPtr = &observer;
226 return 0;
227}
228
229int32_t
230TransmitMixer::SetAudioProcessingModule(AudioProcessing* audioProcessingModule)
231{
232 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
233 "TransmitMixer::SetAudioProcessingModule("
234 "audioProcessingModule=0x%x)",
235 audioProcessingModule);
236 audioproc_ = audioProcessingModule;
237 return 0;
238}
239
Peter Kasting69558702016-01-12 16:26:35 -0800240void TransmitMixer::GetSendCodecInfo(int* max_sample_rate,
241 size_t* max_channels) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000242 *max_sample_rate = 8000;
243 *max_channels = 1;
244 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
245 it.Increment()) {
246 Channel* channel = it.GetChannel();
247 if (channel->Sending()) {
248 CodecInst codec;
249 channel->GetSendCodec(codec);
250 *max_sample_rate = std::max(*max_sample_rate, codec.plfreq);
251 *max_channels = std::max(*max_channels, codec.channels);
252 }
253 }
254}
255
256int32_t
257TransmitMixer::PrepareDemux(const void* audioSamples,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700258 size_t nSamples,
Peter Kasting69558702016-01-12 16:26:35 -0800259 size_t nChannels,
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000260 uint32_t samplesPerSec,
261 uint16_t totalDelayMS,
262 int32_t clockDrift,
263 uint16_t currentMicLevel,
264 bool keyPressed)
265{
266 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
Peter Kastingdce40cf2015-08-24 14:52:23 -0700267 "TransmitMixer::PrepareDemux(nSamples=%" PRIuS ", "
Peter Kasting69558702016-01-12 16:26:35 -0800268 "nChannels=%" PRIuS ", samplesPerSec=%u, totalDelayMS=%u, "
Peter Kastingdce40cf2015-08-24 14:52:23 -0700269 "clockDrift=%d, currentMicLevel=%u)",
270 nSamples, nChannels, samplesPerSec, totalDelayMS, clockDrift,
271 currentMicLevel);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000272
273 // --- Resample input audio and create/store the initial audio frame
274 GenerateAudioFrame(static_cast<const int16_t*>(audioSamples),
275 nSamples,
276 nChannels,
277 samplesPerSec);
278
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000279 // --- Near-end audio processing.
280 ProcessAudio(totalDelayMS, clockDrift, currentMicLevel, keyPressed);
281
282 if (swap_stereo_channels_ && stereo_codec_)
283 // Only bother swapping if we're using a stereo codec.
284 AudioFrameOperations::SwapStereoChannels(&_audioFrame);
285
286 // --- Annoying typing detection (utilizes the APM/VAD decision)
henrik.lundinf00082d2016-12-05 02:22:12 -0800287#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000288 TypingDetection(keyPressed);
289#endif
290
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000291 // --- Mute signal
solenberg1c2af8e2016-03-24 10:36:00 -0700292 AudioFrameOperations::Mute(&_audioFrame, _mute, _mute);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000293
294 // --- Mix with file (does not affect the mixing frequency)
295 if (_filePlaying)
296 {
297 MixOrReplaceAudioWithFile(_audioFrame.sample_rate_hz_);
298 }
299
300 // --- Record to file
301 bool file_recording = false;
302 {
tommi31fc21f2016-01-21 10:37:37 -0800303 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000304 file_recording = _fileRecording;
305 }
306 if (file_recording)
307 {
308 RecordAudioToFile(_audioFrame.sample_rate_hz_);
309 }
310
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000311 // --- Measure audio level of speech after all processing.
312 _audioLevel.ComputeLevel(_audioFrame);
313 return 0;
314}
315
316int32_t
317TransmitMixer::DemuxAndMix()
318{
319 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
320 "TransmitMixer::DemuxAndMix()");
321
322 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
323 it.Increment())
324 {
325 Channel* channelPtr = it.GetChannel();
henrika@webrtc.org66803482014-04-17 10:45:01 +0000326 if (channelPtr->Sending())
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000327 {
328 // Demultiplex makes a copy of its input.
329 channelPtr->Demultiplex(_audioFrame);
330 channelPtr->PrepareEncodeAndSend(_audioFrame.sample_rate_hz_);
331 }
332 }
333 return 0;
334}
335
336void TransmitMixer::DemuxAndMix(const int voe_channels[],
Peter Kasting69558702016-01-12 16:26:35 -0800337 size_t number_of_voe_channels) {
338 for (size_t i = 0; i < number_of_voe_channels; ++i) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000339 voe::ChannelOwner ch = _channelManagerPtr->GetChannel(voe_channels[i]);
340 voe::Channel* channel_ptr = ch.channel();
341 if (channel_ptr) {
henrika@webrtc.org66803482014-04-17 10:45:01 +0000342 if (channel_ptr->Sending()) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000343 // Demultiplex makes a copy of its input.
344 channel_ptr->Demultiplex(_audioFrame);
345 channel_ptr->PrepareEncodeAndSend(_audioFrame.sample_rate_hz_);
346 }
347 }
348 }
349}
350
351int32_t
352TransmitMixer::EncodeAndSend()
353{
354 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
355 "TransmitMixer::EncodeAndSend()");
356
357 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
358 it.Increment())
359 {
360 Channel* channelPtr = it.GetChannel();
henrika@webrtc.org66803482014-04-17 10:45:01 +0000361 if (channelPtr->Sending())
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000362 {
363 channelPtr->EncodeAndSend();
364 }
365 }
366 return 0;
367}
368
369void TransmitMixer::EncodeAndSend(const int voe_channels[],
Peter Kasting69558702016-01-12 16:26:35 -0800370 size_t number_of_voe_channels) {
371 for (size_t i = 0; i < number_of_voe_channels; ++i) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000372 voe::ChannelOwner ch = _channelManagerPtr->GetChannel(voe_channels[i]);
373 voe::Channel* channel_ptr = ch.channel();
henrika@webrtc.org66803482014-04-17 10:45:01 +0000374 if (channel_ptr && channel_ptr->Sending())
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000375 channel_ptr->EncodeAndSend();
376 }
377}
378
379uint32_t TransmitMixer::CaptureLevel() const
380{
381 return _captureLevel;
382}
383
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000384int32_t
385TransmitMixer::StopSend()
386{
387 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
388 "TransmitMixer::StopSend()");
389 _audioLevel.Clear();
390 return 0;
391}
392
393int TransmitMixer::StartPlayingFileAsMicrophone(const char* fileName,
394 bool loop,
395 FileFormats format,
396 int startPosition,
397 float volumeScaling,
398 int stopPosition,
399 const CodecInst* codecInst)
400{
401 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
402 "TransmitMixer::StartPlayingFileAsMicrophone("
403 "fileNameUTF8[]=%s,loop=%d, format=%d, volumeScaling=%5.3f,"
404 " startPosition=%d, stopPosition=%d)", fileName, loop,
405 format, volumeScaling, startPosition, stopPosition);
406
407 if (_filePlaying)
408 {
409 _engineStatisticsPtr->SetLastError(
410 VE_ALREADY_PLAYING, kTraceWarning,
411 "StartPlayingFileAsMicrophone() is already playing");
412 return 0;
413 }
414
tommi31fc21f2016-01-21 10:37:37 -0800415 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000416
417 // Destroy the old instance
kwiberg5a25d952016-08-17 07:31:12 -0700418 if (file_player_) {
419 file_player_->RegisterModuleFileCallback(NULL);
420 file_player_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000421 }
422
423 // Dynamically create the instance
kwiberg5a25d952016-08-17 07:31:12 -0700424 file_player_ =
kwiberg5b356f42016-09-08 04:32:33 -0700425 FilePlayer::CreateFilePlayer(_filePlayerId, (const FileFormats)format);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000426
kwiberg5a25d952016-08-17 07:31:12 -0700427 if (!file_player_) {
428 _engineStatisticsPtr->SetLastError(
429 VE_INVALID_ARGUMENT, kTraceError,
430 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
431 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000432 }
433
434 const uint32_t notificationTime(0);
435
kwiberg5a25d952016-08-17 07:31:12 -0700436 if (file_player_->StartPlayingFile(
437 fileName, loop, startPosition, volumeScaling, notificationTime,
438 stopPosition, (const CodecInst*)codecInst) != 0) {
439 _engineStatisticsPtr->SetLastError(
440 VE_BAD_FILE, kTraceError,
441 "StartPlayingFile() failed to start file playout");
442 file_player_->StopPlayingFile();
443 file_player_.reset();
444 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000445 }
446
kwiberg5a25d952016-08-17 07:31:12 -0700447 file_player_->RegisterModuleFileCallback(this);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000448 _filePlaying = true;
449
450 return 0;
451}
452
453int TransmitMixer::StartPlayingFileAsMicrophone(InStream* stream,
454 FileFormats format,
455 int startPosition,
456 float volumeScaling,
457 int stopPosition,
458 const CodecInst* codecInst)
459{
460 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
461 "TransmitMixer::StartPlayingFileAsMicrophone(format=%d,"
462 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
463 format, volumeScaling, startPosition, stopPosition);
464
465 if (stream == NULL)
466 {
467 _engineStatisticsPtr->SetLastError(
468 VE_BAD_FILE, kTraceError,
469 "StartPlayingFileAsMicrophone() NULL as input stream");
470 return -1;
471 }
472
473 if (_filePlaying)
474 {
475 _engineStatisticsPtr->SetLastError(
476 VE_ALREADY_PLAYING, kTraceWarning,
477 "StartPlayingFileAsMicrophone() is already playing");
478 return 0;
479 }
480
tommi31fc21f2016-01-21 10:37:37 -0800481 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000482
483 // Destroy the old instance
kwiberg5a25d952016-08-17 07:31:12 -0700484 if (file_player_) {
485 file_player_->RegisterModuleFileCallback(NULL);
486 file_player_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000487 }
488
489 // Dynamically create the instance
kwiberg5a25d952016-08-17 07:31:12 -0700490 file_player_ =
kwiberg5b356f42016-09-08 04:32:33 -0700491 FilePlayer::CreateFilePlayer(_filePlayerId, (const FileFormats)format);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000492
kwiberg5a25d952016-08-17 07:31:12 -0700493 if (!file_player_) {
494 _engineStatisticsPtr->SetLastError(
495 VE_INVALID_ARGUMENT, kTraceWarning,
496 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
497 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000498 }
499
500 const uint32_t notificationTime(0);
501
kwiberg4ec01d92016-08-22 08:43:54 -0700502 if (file_player_->StartPlayingFile(stream, startPosition, volumeScaling,
503 notificationTime, stopPosition,
504 (const CodecInst*)codecInst) != 0) {
kwiberg5a25d952016-08-17 07:31:12 -0700505 _engineStatisticsPtr->SetLastError(
506 VE_BAD_FILE, kTraceError,
507 "StartPlayingFile() failed to start file playout");
508 file_player_->StopPlayingFile();
509 file_player_.reset();
510 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000511 }
kwiberg5a25d952016-08-17 07:31:12 -0700512 file_player_->RegisterModuleFileCallback(this);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000513 _filePlaying = true;
514
515 return 0;
516}
517
518int TransmitMixer::StopPlayingFileAsMicrophone()
519{
520 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
521 "TransmitMixer::StopPlayingFileAsMicrophone()");
522
523 if (!_filePlaying)
524 {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000525 return 0;
526 }
527
tommi31fc21f2016-01-21 10:37:37 -0800528 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000529
kwiberg5a25d952016-08-17 07:31:12 -0700530 if (file_player_->StopPlayingFile() != 0) {
531 _engineStatisticsPtr->SetLastError(
532 VE_CANNOT_STOP_PLAYOUT, kTraceError,
533 "StopPlayingFile() couldnot stop playing file");
534 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000535 }
536
kwiberg5a25d952016-08-17 07:31:12 -0700537 file_player_->RegisterModuleFileCallback(NULL);
538 file_player_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000539 _filePlaying = false;
540
541 return 0;
542}
543
544int TransmitMixer::IsPlayingFileAsMicrophone() const
545{
546 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
547 "TransmitMixer::IsPlayingFileAsMicrophone()");
548 return _filePlaying;
549}
550
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000551int TransmitMixer::StartRecordingMicrophone(const char* fileName,
552 const CodecInst* codecInst)
553{
554 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
555 "TransmitMixer::StartRecordingMicrophone(fileName=%s)",
556 fileName);
557
tommi31fc21f2016-01-21 10:37:37 -0800558 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000559
560 if (_fileRecording)
561 {
562 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
563 "StartRecordingMicrophone() is already recording");
564 return 0;
565 }
566
567 FileFormats format;
568 const uint32_t notificationTime(0); // Not supported in VoE
569 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
570
Peter Kasting69558702016-01-12 16:26:35 -0800571 if (codecInst != NULL && codecInst->channels > 2)
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000572 {
573 _engineStatisticsPtr->SetLastError(
574 VE_BAD_ARGUMENT, kTraceError,
575 "StartRecordingMicrophone() invalid compression");
576 return (-1);
577 }
578 if (codecInst == NULL)
579 {
580 format = kFileFormatPcm16kHzFile;
581 codecInst = &dummyCodec;
582 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
583 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
584 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
585 {
586 format = kFileFormatWavFile;
587 } else
588 {
589 format = kFileFormatCompressedFile;
590 }
591
592 // Destroy the old instance
kwiberg5a25d952016-08-17 07:31:12 -0700593 if (file_recorder_) {
594 file_recorder_->RegisterModuleFileCallback(NULL);
595 file_recorder_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000596 }
597
kwiberg5a25d952016-08-17 07:31:12 -0700598 file_recorder_ = FileRecorder::CreateFileRecorder(
599 _fileRecorderId, (const FileFormats)format);
600 if (!file_recorder_) {
601 _engineStatisticsPtr->SetLastError(
602 VE_INVALID_ARGUMENT, kTraceError,
603 "StartRecordingMicrophone() fileRecorder format isnot correct");
604 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000605 }
606
kwiberg5a25d952016-08-17 07:31:12 -0700607 if (file_recorder_->StartRecordingAudioFile(
608 fileName, (const CodecInst&)*codecInst, notificationTime) != 0) {
609 _engineStatisticsPtr->SetLastError(
610 VE_BAD_FILE, kTraceError,
611 "StartRecordingAudioFile() failed to start file recording");
612 file_recorder_->StopRecording();
613 file_recorder_.reset();
614 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000615 }
kwiberg5a25d952016-08-17 07:31:12 -0700616 file_recorder_->RegisterModuleFileCallback(this);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000617 _fileRecording = true;
618
619 return 0;
620}
621
622int TransmitMixer::StartRecordingMicrophone(OutStream* stream,
623 const CodecInst* codecInst)
624{
625 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
626 "TransmitMixer::StartRecordingMicrophone()");
627
tommi31fc21f2016-01-21 10:37:37 -0800628 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000629
630 if (_fileRecording)
631 {
632 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
633 "StartRecordingMicrophone() is already recording");
634 return 0;
635 }
636
637 FileFormats format;
638 const uint32_t notificationTime(0); // Not supported in VoE
639 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
640
641 if (codecInst != NULL && codecInst->channels != 1)
642 {
643 _engineStatisticsPtr->SetLastError(
644 VE_BAD_ARGUMENT, kTraceError,
645 "StartRecordingMicrophone() invalid compression");
646 return (-1);
647 }
648 if (codecInst == NULL)
649 {
650 format = kFileFormatPcm16kHzFile;
651 codecInst = &dummyCodec;
652 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
653 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
654 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
655 {
656 format = kFileFormatWavFile;
657 } else
658 {
659 format = kFileFormatCompressedFile;
660 }
661
662 // Destroy the old instance
kwiberg5a25d952016-08-17 07:31:12 -0700663 if (file_recorder_) {
664 file_recorder_->RegisterModuleFileCallback(NULL);
665 file_recorder_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000666 }
667
kwiberg5a25d952016-08-17 07:31:12 -0700668 file_recorder_ = FileRecorder::CreateFileRecorder(
669 _fileRecorderId, (const FileFormats)format);
670 if (!file_recorder_) {
671 _engineStatisticsPtr->SetLastError(
672 VE_INVALID_ARGUMENT, kTraceError,
673 "StartRecordingMicrophone() fileRecorder format isnot correct");
674 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000675 }
676
kwiberg4ec01d92016-08-22 08:43:54 -0700677 if (file_recorder_->StartRecordingAudioFile(stream, *codecInst,
kwiberg5a25d952016-08-17 07:31:12 -0700678 notificationTime) != 0) {
679 _engineStatisticsPtr->SetLastError(
680 VE_BAD_FILE, kTraceError,
681 "StartRecordingAudioFile() failed to start file recording");
682 file_recorder_->StopRecording();
683 file_recorder_.reset();
684 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000685 }
686
kwiberg5a25d952016-08-17 07:31:12 -0700687 file_recorder_->RegisterModuleFileCallback(this);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000688 _fileRecording = true;
689
690 return 0;
691}
692
693
694int TransmitMixer::StopRecordingMicrophone()
695{
696 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
697 "TransmitMixer::StopRecordingMicrophone()");
698
tommi31fc21f2016-01-21 10:37:37 -0800699 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000700
701 if (!_fileRecording)
702 {
703 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
704 "StopRecordingMicrophone() isnot recording");
705 return 0;
706 }
707
kwiberg5a25d952016-08-17 07:31:12 -0700708 if (file_recorder_->StopRecording() != 0) {
709 _engineStatisticsPtr->SetLastError(
710 VE_STOP_RECORDING_FAILED, kTraceError,
711 "StopRecording(), could not stop recording");
712 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000713 }
kwiberg5a25d952016-08-17 07:31:12 -0700714 file_recorder_->RegisterModuleFileCallback(NULL);
715 file_recorder_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000716 _fileRecording = false;
717
718 return 0;
719}
720
721int TransmitMixer::StartRecordingCall(const char* fileName,
722 const CodecInst* codecInst)
723{
724 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
725 "TransmitMixer::StartRecordingCall(fileName=%s)", fileName);
726
727 if (_fileCallRecording)
728 {
729 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
730 "StartRecordingCall() is already recording");
731 return 0;
732 }
733
734 FileFormats format;
735 const uint32_t notificationTime(0); // Not supported in VoE
736 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
737
738 if (codecInst != NULL && codecInst->channels != 1)
739 {
740 _engineStatisticsPtr->SetLastError(
741 VE_BAD_ARGUMENT, kTraceError,
742 "StartRecordingCall() invalid compression");
743 return (-1);
744 }
745 if (codecInst == NULL)
746 {
747 format = kFileFormatPcm16kHzFile;
748 codecInst = &dummyCodec;
749 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
750 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
751 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
752 {
753 format = kFileFormatWavFile;
754 } else
755 {
756 format = kFileFormatCompressedFile;
757 }
758
tommi31fc21f2016-01-21 10:37:37 -0800759 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000760
761 // Destroy the old instance
kwiberg5a25d952016-08-17 07:31:12 -0700762 if (file_call_recorder_) {
763 file_call_recorder_->RegisterModuleFileCallback(NULL);
764 file_call_recorder_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000765 }
766
kwiberg5a25d952016-08-17 07:31:12 -0700767 file_call_recorder_ = FileRecorder::CreateFileRecorder(
768 _fileCallRecorderId, (const FileFormats)format);
769 if (!file_call_recorder_) {
770 _engineStatisticsPtr->SetLastError(
771 VE_INVALID_ARGUMENT, kTraceError,
772 "StartRecordingCall() fileRecorder format isnot correct");
773 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000774 }
775
kwiberg5a25d952016-08-17 07:31:12 -0700776 if (file_call_recorder_->StartRecordingAudioFile(
777 fileName, (const CodecInst&)*codecInst, notificationTime) != 0) {
778 _engineStatisticsPtr->SetLastError(
779 VE_BAD_FILE, kTraceError,
780 "StartRecordingAudioFile() failed to start file recording");
781 file_call_recorder_->StopRecording();
782 file_call_recorder_.reset();
783 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000784 }
kwiberg5a25d952016-08-17 07:31:12 -0700785 file_call_recorder_->RegisterModuleFileCallback(this);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000786 _fileCallRecording = true;
787
788 return 0;
789}
790
791int TransmitMixer::StartRecordingCall(OutStream* stream,
792 const CodecInst* codecInst)
793{
794 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
795 "TransmitMixer::StartRecordingCall()");
796
797 if (_fileCallRecording)
798 {
799 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
800 "StartRecordingCall() is already recording");
801 return 0;
802 }
803
804 FileFormats format;
805 const uint32_t notificationTime(0); // Not supported in VoE
806 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
807
808 if (codecInst != NULL && codecInst->channels != 1)
809 {
810 _engineStatisticsPtr->SetLastError(
811 VE_BAD_ARGUMENT, kTraceError,
812 "StartRecordingCall() invalid compression");
813 return (-1);
814 }
815 if (codecInst == NULL)
816 {
817 format = kFileFormatPcm16kHzFile;
818 codecInst = &dummyCodec;
819 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
820 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
821 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
822 {
823 format = kFileFormatWavFile;
824 } else
825 {
826 format = kFileFormatCompressedFile;
827 }
828
tommi31fc21f2016-01-21 10:37:37 -0800829 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000830
831 // Destroy the old instance
kwiberg5a25d952016-08-17 07:31:12 -0700832 if (file_call_recorder_) {
833 file_call_recorder_->RegisterModuleFileCallback(NULL);
834 file_call_recorder_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000835 }
836
kwiberg5a25d952016-08-17 07:31:12 -0700837 file_call_recorder_ = FileRecorder::CreateFileRecorder(
838 _fileCallRecorderId, (const FileFormats)format);
839 if (!file_call_recorder_) {
840 _engineStatisticsPtr->SetLastError(
841 VE_INVALID_ARGUMENT, kTraceError,
842 "StartRecordingCall() fileRecorder format isnot correct");
843 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000844 }
845
kwiberg4ec01d92016-08-22 08:43:54 -0700846 if (file_call_recorder_->StartRecordingAudioFile(stream, *codecInst,
kwiberg5a25d952016-08-17 07:31:12 -0700847 notificationTime) != 0) {
848 _engineStatisticsPtr->SetLastError(
849 VE_BAD_FILE, kTraceError,
850 "StartRecordingAudioFile() failed to start file recording");
851 file_call_recorder_->StopRecording();
852 file_call_recorder_.reset();
853 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000854 }
855
kwiberg5a25d952016-08-17 07:31:12 -0700856 file_call_recorder_->RegisterModuleFileCallback(this);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000857 _fileCallRecording = true;
858
859 return 0;
860}
861
862int TransmitMixer::StopRecordingCall()
863{
864 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
865 "TransmitMixer::StopRecordingCall()");
866
867 if (!_fileCallRecording)
868 {
869 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
870 "StopRecordingCall() file isnot recording");
871 return -1;
872 }
873
tommi31fc21f2016-01-21 10:37:37 -0800874 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000875
kwiberg5a25d952016-08-17 07:31:12 -0700876 if (file_call_recorder_->StopRecording() != 0) {
877 _engineStatisticsPtr->SetLastError(
878 VE_STOP_RECORDING_FAILED, kTraceError,
879 "StopRecording(), could not stop recording");
880 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000881 }
882
kwiberg5a25d952016-08-17 07:31:12 -0700883 file_call_recorder_->RegisterModuleFileCallback(NULL);
884 file_call_recorder_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000885 _fileCallRecording = false;
886
887 return 0;
888}
889
890void
891TransmitMixer::SetMixWithMicStatus(bool mix)
892{
893 _mixFileWithMicrophone = mix;
894}
895
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000896int
897TransmitMixer::SetMute(bool enable)
898{
899 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
900 "TransmitMixer::SetMute(enable=%d)", enable);
901 _mute = enable;
902 return 0;
903}
904
905bool
906TransmitMixer::Mute() const
907{
908 return _mute;
909}
910
911int8_t TransmitMixer::AudioLevel() const
912{
913 // Speech + file level [0,9]
914 return _audioLevel.Level();
915}
916
917int16_t TransmitMixer::AudioLevelFullRange() const
918{
919 // Speech + file level [0,32767]
920 return _audioLevel.LevelFullRange();
921}
922
923bool TransmitMixer::IsRecordingCall()
924{
925 return _fileCallRecording;
926}
927
928bool TransmitMixer::IsRecordingMic()
929{
tommi31fc21f2016-01-21 10:37:37 -0800930 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000931 return _fileRecording;
932}
933
934void TransmitMixer::GenerateAudioFrame(const int16_t* audio,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700935 size_t samples_per_channel,
Peter Kasting69558702016-01-12 16:26:35 -0800936 size_t num_channels,
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000937 int sample_rate_hz) {
938 int codec_rate;
Peter Kasting69558702016-01-12 16:26:35 -0800939 size_t num_codec_channels;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000940 GetSendCodecInfo(&codec_rate, &num_codec_channels);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000941 stereo_codec_ = num_codec_channels == 2;
942
Alejandro Luebscdfe20b2015-09-23 12:49:12 -0700943 // We want to process at the lowest rate possible without losing information.
944 // Choose the lowest native rate at least equal to the input and codec rates.
945 const int min_processing_rate = std::min(sample_rate_hz, codec_rate);
946 for (size_t i = 0; i < AudioProcessing::kNumNativeSampleRates; ++i) {
947 _audioFrame.sample_rate_hz_ = AudioProcessing::kNativeSampleRatesHz[i];
948 if (_audioFrame.sample_rate_hz_ >= min_processing_rate) {
949 break;
950 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000951 }
Alejandro Luebscdfe20b2015-09-23 12:49:12 -0700952 _audioFrame.num_channels_ = std::min(num_channels, num_codec_channels);
953 RemixAndResample(audio, samples_per_channel, num_channels, sample_rate_hz,
954 &resampler_, &_audioFrame);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000955}
956
957int32_t TransmitMixer::RecordAudioToFile(
958 uint32_t mixingFrequency)
959{
tommi31fc21f2016-01-21 10:37:37 -0800960 rtc::CritScope cs(&_critSect);
kwiberg5a25d952016-08-17 07:31:12 -0700961 if (!file_recorder_) {
962 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
963 "TransmitMixer::RecordAudioToFile() filerecorder doesnot"
964 "exist");
965 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000966 }
967
kwiberg5a25d952016-08-17 07:31:12 -0700968 if (file_recorder_->RecordAudioToFile(_audioFrame) != 0) {
969 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
970 "TransmitMixer::RecordAudioToFile() file recording"
971 "failed");
972 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000973 }
974
975 return 0;
976}
977
978int32_t TransmitMixer::MixOrReplaceAudioWithFile(
979 int mixingFrequency)
980{
kwibergb7f89d62016-02-17 10:04:18 -0800981 std::unique_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000982
Peter Kastingdce40cf2015-08-24 14:52:23 -0700983 size_t fileSamples(0);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000984 {
tommi31fc21f2016-01-21 10:37:37 -0800985 rtc::CritScope cs(&_critSect);
kwiberg5a25d952016-08-17 07:31:12 -0700986 if (!file_player_) {
987 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
988 "TransmitMixer::MixOrReplaceAudioWithFile()"
989 "fileplayer doesnot exist");
990 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000991 }
992
kwiberg4ec01d92016-08-22 08:43:54 -0700993 if (file_player_->Get10msAudioFromFile(fileBuffer.get(), &fileSamples,
kwiberg5a25d952016-08-17 07:31:12 -0700994 mixingFrequency) == -1) {
995 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
996 "TransmitMixer::MixOrReplaceAudioWithFile() file"
997 " mixing failed");
998 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000999 }
1000 }
1001
1002 assert(_audioFrame.samples_per_channel_ == fileSamples);
1003
1004 if (_mixFileWithMicrophone)
1005 {
1006 // Currently file stream is always mono.
1007 // TODO(xians): Change the code when FilePlayer supports real stereo.
1008 MixWithSat(_audioFrame.data_,
1009 _audioFrame.num_channels_,
1010 fileBuffer.get(),
1011 1,
1012 fileSamples);
1013 } else
1014 {
1015 // Replace ACM audio with file.
1016 // Currently file stream is always mono.
1017 // TODO(xians): Change the code when FilePlayer supports real stereo.
1018 _audioFrame.UpdateFrame(-1,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00001019 0xFFFFFFFF,
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001020 fileBuffer.get(),
1021 fileSamples,
1022 mixingFrequency,
1023 AudioFrame::kNormalSpeech,
1024 AudioFrame::kVadUnknown,
1025 1);
1026 }
1027 return 0;
1028}
1029
1030void TransmitMixer::ProcessAudio(int delay_ms, int clock_drift,
1031 int current_mic_level, bool key_pressed) {
1032 if (audioproc_->set_stream_delay_ms(delay_ms) != 0) {
pbosad856222015-11-27 09:48:36 -08001033 // Silently ignore this failure to avoid flooding the logs.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001034 }
1035
1036 GainControl* agc = audioproc_->gain_control();
1037 if (agc->set_stream_analog_level(current_mic_level) != 0) {
pbosad856222015-11-27 09:48:36 -08001038 LOG(LS_ERROR) << "set_stream_analog_level failed: current_mic_level = "
1039 << current_mic_level;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001040 assert(false);
1041 }
1042
1043 EchoCancellation* aec = audioproc_->echo_cancellation();
1044 if (aec->is_drift_compensation_enabled()) {
1045 aec->set_stream_drift_samples(clock_drift);
1046 }
1047
1048 audioproc_->set_stream_key_pressed(key_pressed);
1049
1050 int err = audioproc_->ProcessStream(&_audioFrame);
1051 if (err != 0) {
1052 LOG(LS_ERROR) << "ProcessStream() error: " << err;
1053 assert(false);
1054 }
1055
1056 // Store new capture level. Only updated when analog AGC is enabled.
1057 _captureLevel = agc->stream_analog_level();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001058}
1059
henrik.lundinf00082d2016-12-05 02:22:12 -08001060#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001061void TransmitMixer::TypingDetection(bool keyPressed)
1062{
1063 // We let the VAD determine if we're using this feature or not.
1064 if (_audioFrame.vad_activity_ == AudioFrame::kVadUnknown) {
1065 return;
1066 }
1067
1068 bool vadActive = _audioFrame.vad_activity_ == AudioFrame::kVadActive;
1069 if (_typingDetection.Process(keyPressed, vadActive)) {
tommi31fc21f2016-01-21 10:37:37 -08001070 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001071 _typingNoiseWarningPending = true;
1072 _typingNoiseDetected = true;
1073 } else {
tommi31fc21f2016-01-21 10:37:37 -08001074 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001075 // If there is already a warning pending, do not change the state.
1076 // Otherwise set a warning pending if last callback was for noise detected.
1077 if (!_typingNoiseWarningPending && _typingNoiseDetected) {
1078 _typingNoiseWarningPending = true;
1079 _typingNoiseDetected = false;
1080 }
1081 }
1082}
1083#endif
1084
henrik.lundinf00082d2016-12-05 02:22:12 -08001085#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001086int TransmitMixer::TimeSinceLastTyping(int &seconds)
1087{
1088 // We check in VoEAudioProcessingImpl that this is only called when
1089 // typing detection is active.
1090 seconds = _typingDetection.TimeSinceLastDetectionInSeconds();
1091 return 0;
1092}
1093#endif
1094
henrik.lundinf00082d2016-12-05 02:22:12 -08001095#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001096int TransmitMixer::SetTypingDetectionParameters(int timeWindow,
1097 int costPerTyping,
1098 int reportingThreshold,
1099 int penaltyDecay,
1100 int typeEventDelay)
1101{
1102 _typingDetection.SetParameters(timeWindow,
1103 costPerTyping,
1104 reportingThreshold,
1105 penaltyDecay,
1106 typeEventDelay,
1107 0);
1108 return 0;
1109}
1110#endif
1111
1112void TransmitMixer::EnableStereoChannelSwapping(bool enable) {
1113 swap_stereo_channels_ = enable;
1114}
1115
1116bool TransmitMixer::IsStereoChannelSwappingEnabled() {
1117 return swap_stereo_channels_;
1118}
1119
1120} // namespace voe
1121} // namespace webrtc