blob: be6297287b8bef28e06b654923f2d2c8be483669 [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
Peter Kastingdce40cf2015-08-24 14:52:23 -070015#include "webrtc/base/format_macros.h"
pbosad856222015-11-27 09:48:36 -080016#include "webrtc/base/logging.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010017#include "webrtc/modules/utility/include/audio_frame_operations.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"
22#include "webrtc/voice_engine/include/voe_external_media.h"
23#include "webrtc/voice_engine/statistics.h"
24#include "webrtc/voice_engine/utility.h"
25#include "webrtc/voice_engine/voe_base_impl.h"
26
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000027namespace webrtc {
28namespace voe {
29
30// TODO(ajm): The thread safety of this is dubious...
31void
32TransmitMixer::OnPeriodicProcess()
33{
34 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
35 "TransmitMixer::OnPeriodicProcess()");
36
37#if defined(WEBRTC_VOICE_ENGINE_TYPING_DETECTION)
solenberg302c9782015-11-24 06:28:22 -080038 bool send_typing_noise_warning = false;
39 bool typing_noise_detected = false;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000040 {
tommi31fc21f2016-01-21 10:37:37 -080041 rtc::CritScope cs(&_critSect);
solenberg302c9782015-11-24 06:28:22 -080042 if (_typingNoiseWarningPending) {
43 send_typing_noise_warning = true;
44 typing_noise_detected = _typingNoiseDetected;
45 _typingNoiseWarningPending = false;
46 }
47 }
48 if (send_typing_noise_warning) {
tommi31fc21f2016-01-21 10:37:37 -080049 rtc::CritScope cs(&_callbackCritSect);
solenberg302c9782015-11-24 06:28:22 -080050 if (_voiceEngineObserverPtr) {
51 if (typing_noise_detected) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000052 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
53 "TransmitMixer::OnPeriodicProcess() => "
54 "CallbackOnError(VE_TYPING_NOISE_WARNING)");
55 _voiceEngineObserverPtr->CallbackOnError(
56 -1,
57 VE_TYPING_NOISE_WARNING);
58 } else {
59 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
60 "TransmitMixer::OnPeriodicProcess() => "
61 "CallbackOnError(VE_TYPING_NOISE_OFF_WARNING)");
62 _voiceEngineObserverPtr->CallbackOnError(
63 -1,
64 VE_TYPING_NOISE_OFF_WARNING);
65 }
66 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000067 }
68#endif
69
70 bool saturationWarning = false;
71 {
72 // Modify |_saturationWarning| under lock to avoid conflict with write op
73 // in ProcessAudio and also ensure that we don't hold the lock during the
74 // callback.
tommi31fc21f2016-01-21 10:37:37 -080075 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000076 saturationWarning = _saturationWarning;
77 if (_saturationWarning)
78 _saturationWarning = false;
79 }
80
81 if (saturationWarning)
82 {
tommi31fc21f2016-01-21 10:37:37 -080083 rtc::CritScope cs(&_callbackCritSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000084 if (_voiceEngineObserverPtr)
85 {
86 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
87 "TransmitMixer::OnPeriodicProcess() =>"
88 " CallbackOnError(VE_SATURATION_WARNING)");
89 _voiceEngineObserverPtr->CallbackOnError(-1, VE_SATURATION_WARNING);
90 }
91 }
92}
93
94
95void TransmitMixer::PlayNotification(int32_t id,
96 uint32_t durationMs)
97{
98 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
99 "TransmitMixer::PlayNotification(id=%d, durationMs=%d)",
100 id, durationMs);
101
102 // Not implement yet
103}
104
105void TransmitMixer::RecordNotification(int32_t id,
106 uint32_t durationMs)
107{
108 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1),
109 "TransmitMixer::RecordNotification(id=%d, durationMs=%d)",
110 id, durationMs);
111
112 // Not implement yet
113}
114
115void TransmitMixer::PlayFileEnded(int32_t id)
116{
117 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
118 "TransmitMixer::PlayFileEnded(id=%d)", id);
119
120 assert(id == _filePlayerId);
121
tommi31fc21f2016-01-21 10:37:37 -0800122 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000123
124 _filePlaying = false;
125 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1),
126 "TransmitMixer::PlayFileEnded() =>"
127 "file player module is shutdown");
128}
129
130void
131TransmitMixer::RecordFileEnded(int32_t id)
132{
133 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
134 "TransmitMixer::RecordFileEnded(id=%d)", id);
135
136 if (id == _fileRecorderId)
137 {
tommi31fc21f2016-01-21 10:37:37 -0800138 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000139 _fileRecording = false;
140 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1),
141 "TransmitMixer::RecordFileEnded() => fileRecorder module"
142 "is shutdown");
143 } else if (id == _fileCallRecorderId)
144 {
tommi31fc21f2016-01-21 10:37:37 -0800145 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000146 _fileCallRecording = false;
147 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1),
148 "TransmitMixer::RecordFileEnded() => fileCallRecorder"
149 "module is shutdown");
150 }
151}
152
153int32_t
154TransmitMixer::Create(TransmitMixer*& mixer, uint32_t instanceId)
155{
156 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, -1),
157 "TransmitMixer::Create(instanceId=%d)", instanceId);
158 mixer = new TransmitMixer(instanceId);
159 if (mixer == NULL)
160 {
161 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, -1),
162 "TransmitMixer::Create() unable to allocate memory"
163 "for mixer");
164 return -1;
165 }
166 return 0;
167}
168
169void
170TransmitMixer::Destroy(TransmitMixer*& mixer)
171{
172 if (mixer)
173 {
174 delete mixer;
175 mixer = NULL;
176 }
177}
178
179TransmitMixer::TransmitMixer(uint32_t instanceId) :
180 _engineStatisticsPtr(NULL),
181 _channelManagerPtr(NULL),
182 audioproc_(NULL),
183 _voiceEngineObserverPtr(NULL),
184 _processThreadPtr(NULL),
185 _filePlayerPtr(NULL),
186 _fileRecorderPtr(NULL),
187 _fileCallRecorderPtr(NULL),
188 // Avoid conflict with other channels by adding 1024 - 1026,
189 // won't use as much as 1024 channels.
190 _filePlayerId(instanceId + 1024),
191 _fileRecorderId(instanceId + 1025),
192 _fileCallRecorderId(instanceId + 1026),
193 _filePlaying(false),
194 _fileRecording(false),
195 _fileCallRecording(false),
196 _audioLevel(),
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000197#ifdef WEBRTC_VOICE_ENGINE_TYPING_DETECTION
198 _typingNoiseWarningPending(false),
199 _typingNoiseDetected(false),
200#endif
201 _saturationWarning(false),
202 _instanceId(instanceId),
203 _mixFileWithMicrophone(false),
204 _captureLevel(0),
205 external_postproc_ptr_(NULL),
206 external_preproc_ptr_(NULL),
207 _mute(false),
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000208 stereo_codec_(false),
209 swap_stereo_channels_(false)
210{
211 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1),
212 "TransmitMixer::TransmitMixer() - ctor");
213}
214
215TransmitMixer::~TransmitMixer()
216{
217 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1),
218 "TransmitMixer::~TransmitMixer() - dtor");
219 _monitorModule.DeRegisterObserver();
220 if (_processThreadPtr)
221 {
222 _processThreadPtr->DeRegisterModule(&_monitorModule);
223 }
224 DeRegisterExternalMediaProcessing(kRecordingAllChannelsMixed);
225 DeRegisterExternalMediaProcessing(kRecordingPreprocessing);
226 {
tommi31fc21f2016-01-21 10:37:37 -0800227 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000228 if (_fileRecorderPtr)
229 {
230 _fileRecorderPtr->RegisterModuleFileCallback(NULL);
231 _fileRecorderPtr->StopRecording();
232 FileRecorder::DestroyFileRecorder(_fileRecorderPtr);
233 _fileRecorderPtr = NULL;
234 }
235 if (_fileCallRecorderPtr)
236 {
237 _fileCallRecorderPtr->RegisterModuleFileCallback(NULL);
238 _fileCallRecorderPtr->StopRecording();
239 FileRecorder::DestroyFileRecorder(_fileCallRecorderPtr);
240 _fileCallRecorderPtr = NULL;
241 }
242 if (_filePlayerPtr)
243 {
244 _filePlayerPtr->RegisterModuleFileCallback(NULL);
245 _filePlayerPtr->StopPlayingFile();
246 FilePlayer::DestroyFilePlayer(_filePlayerPtr);
247 _filePlayerPtr = NULL;
248 }
249 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000250}
251
252int32_t
253TransmitMixer::SetEngineInformation(ProcessThread& processThread,
254 Statistics& engineStatistics,
255 ChannelManager& channelManager)
256{
257 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
258 "TransmitMixer::SetEngineInformation()");
259
260 _processThreadPtr = &processThread;
261 _engineStatisticsPtr = &engineStatistics;
262 _channelManagerPtr = &channelManager;
263
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000264 _processThreadPtr->RegisterModule(&_monitorModule);
265 _monitorModule.RegisterObserver(*this);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000266
267 return 0;
268}
269
270int32_t
271TransmitMixer::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
272{
273 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
274 "TransmitMixer::RegisterVoiceEngineObserver()");
tommi31fc21f2016-01-21 10:37:37 -0800275 rtc::CritScope cs(&_callbackCritSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000276
277 if (_voiceEngineObserverPtr)
278 {
279 _engineStatisticsPtr->SetLastError(
280 VE_INVALID_OPERATION, kTraceError,
281 "RegisterVoiceEngineObserver() observer already enabled");
282 return -1;
283 }
284 _voiceEngineObserverPtr = &observer;
285 return 0;
286}
287
288int32_t
289TransmitMixer::SetAudioProcessingModule(AudioProcessing* audioProcessingModule)
290{
291 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
292 "TransmitMixer::SetAudioProcessingModule("
293 "audioProcessingModule=0x%x)",
294 audioProcessingModule);
295 audioproc_ = audioProcessingModule;
296 return 0;
297}
298
Peter Kasting69558702016-01-12 16:26:35 -0800299void TransmitMixer::GetSendCodecInfo(int* max_sample_rate,
300 size_t* max_channels) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000301 *max_sample_rate = 8000;
302 *max_channels = 1;
303 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
304 it.Increment()) {
305 Channel* channel = it.GetChannel();
306 if (channel->Sending()) {
307 CodecInst codec;
308 channel->GetSendCodec(codec);
309 *max_sample_rate = std::max(*max_sample_rate, codec.plfreq);
310 *max_channels = std::max(*max_channels, codec.channels);
311 }
312 }
313}
314
315int32_t
316TransmitMixer::PrepareDemux(const void* audioSamples,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700317 size_t nSamples,
Peter Kasting69558702016-01-12 16:26:35 -0800318 size_t nChannels,
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000319 uint32_t samplesPerSec,
320 uint16_t totalDelayMS,
321 int32_t clockDrift,
322 uint16_t currentMicLevel,
323 bool keyPressed)
324{
325 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
Peter Kastingdce40cf2015-08-24 14:52:23 -0700326 "TransmitMixer::PrepareDemux(nSamples=%" PRIuS ", "
Peter Kasting69558702016-01-12 16:26:35 -0800327 "nChannels=%" PRIuS ", samplesPerSec=%u, totalDelayMS=%u, "
Peter Kastingdce40cf2015-08-24 14:52:23 -0700328 "clockDrift=%d, currentMicLevel=%u)",
329 nSamples, nChannels, samplesPerSec, totalDelayMS, clockDrift,
330 currentMicLevel);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000331
332 // --- Resample input audio and create/store the initial audio frame
333 GenerateAudioFrame(static_cast<const int16_t*>(audioSamples),
334 nSamples,
335 nChannels,
336 samplesPerSec);
337
338 {
tommi31fc21f2016-01-21 10:37:37 -0800339 rtc::CritScope cs(&_callbackCritSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000340 if (external_preproc_ptr_) {
341 external_preproc_ptr_->Process(-1, kRecordingPreprocessing,
342 _audioFrame.data_,
343 _audioFrame.samples_per_channel_,
344 _audioFrame.sample_rate_hz_,
345 _audioFrame.num_channels_ == 2);
346 }
347 }
348
349 // --- Near-end audio processing.
350 ProcessAudio(totalDelayMS, clockDrift, currentMicLevel, keyPressed);
351
352 if (swap_stereo_channels_ && stereo_codec_)
353 // Only bother swapping if we're using a stereo codec.
354 AudioFrameOperations::SwapStereoChannels(&_audioFrame);
355
356 // --- Annoying typing detection (utilizes the APM/VAD decision)
357#ifdef WEBRTC_VOICE_ENGINE_TYPING_DETECTION
358 TypingDetection(keyPressed);
359#endif
360
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000361 // --- Mute signal
solenberg1c2af8e2016-03-24 10:36:00 -0700362 AudioFrameOperations::Mute(&_audioFrame, _mute, _mute);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000363
364 // --- Mix with file (does not affect the mixing frequency)
365 if (_filePlaying)
366 {
367 MixOrReplaceAudioWithFile(_audioFrame.sample_rate_hz_);
368 }
369
370 // --- Record to file
371 bool file_recording = false;
372 {
tommi31fc21f2016-01-21 10:37:37 -0800373 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000374 file_recording = _fileRecording;
375 }
376 if (file_recording)
377 {
378 RecordAudioToFile(_audioFrame.sample_rate_hz_);
379 }
380
381 {
tommi31fc21f2016-01-21 10:37:37 -0800382 rtc::CritScope cs(&_callbackCritSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000383 if (external_postproc_ptr_) {
384 external_postproc_ptr_->Process(-1, kRecordingAllChannelsMixed,
385 _audioFrame.data_,
386 _audioFrame.samples_per_channel_,
387 _audioFrame.sample_rate_hz_,
388 _audioFrame.num_channels_ == 2);
389 }
390 }
391
392 // --- Measure audio level of speech after all processing.
393 _audioLevel.ComputeLevel(_audioFrame);
394 return 0;
395}
396
397int32_t
398TransmitMixer::DemuxAndMix()
399{
400 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
401 "TransmitMixer::DemuxAndMix()");
402
403 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
404 it.Increment())
405 {
406 Channel* channelPtr = it.GetChannel();
henrika@webrtc.org66803482014-04-17 10:45:01 +0000407 if (channelPtr->Sending())
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000408 {
409 // Demultiplex makes a copy of its input.
410 channelPtr->Demultiplex(_audioFrame);
411 channelPtr->PrepareEncodeAndSend(_audioFrame.sample_rate_hz_);
412 }
413 }
414 return 0;
415}
416
417void TransmitMixer::DemuxAndMix(const int voe_channels[],
Peter Kasting69558702016-01-12 16:26:35 -0800418 size_t number_of_voe_channels) {
419 for (size_t i = 0; i < number_of_voe_channels; ++i) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000420 voe::ChannelOwner ch = _channelManagerPtr->GetChannel(voe_channels[i]);
421 voe::Channel* channel_ptr = ch.channel();
422 if (channel_ptr) {
henrika@webrtc.org66803482014-04-17 10:45:01 +0000423 if (channel_ptr->Sending()) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000424 // Demultiplex makes a copy of its input.
425 channel_ptr->Demultiplex(_audioFrame);
426 channel_ptr->PrepareEncodeAndSend(_audioFrame.sample_rate_hz_);
427 }
428 }
429 }
430}
431
432int32_t
433TransmitMixer::EncodeAndSend()
434{
435 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
436 "TransmitMixer::EncodeAndSend()");
437
438 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
439 it.Increment())
440 {
441 Channel* channelPtr = it.GetChannel();
henrika@webrtc.org66803482014-04-17 10:45:01 +0000442 if (channelPtr->Sending())
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000443 {
444 channelPtr->EncodeAndSend();
445 }
446 }
447 return 0;
448}
449
450void TransmitMixer::EncodeAndSend(const int voe_channels[],
Peter Kasting69558702016-01-12 16:26:35 -0800451 size_t number_of_voe_channels) {
452 for (size_t i = 0; i < number_of_voe_channels; ++i) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000453 voe::ChannelOwner ch = _channelManagerPtr->GetChannel(voe_channels[i]);
454 voe::Channel* channel_ptr = ch.channel();
henrika@webrtc.org66803482014-04-17 10:45:01 +0000455 if (channel_ptr && channel_ptr->Sending())
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000456 channel_ptr->EncodeAndSend();
457 }
458}
459
460uint32_t TransmitMixer::CaptureLevel() const
461{
462 return _captureLevel;
463}
464
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000465int32_t
466TransmitMixer::StopSend()
467{
468 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
469 "TransmitMixer::StopSend()");
470 _audioLevel.Clear();
471 return 0;
472}
473
474int TransmitMixer::StartPlayingFileAsMicrophone(const char* fileName,
475 bool loop,
476 FileFormats format,
477 int startPosition,
478 float volumeScaling,
479 int stopPosition,
480 const CodecInst* codecInst)
481{
482 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
483 "TransmitMixer::StartPlayingFileAsMicrophone("
484 "fileNameUTF8[]=%s,loop=%d, format=%d, volumeScaling=%5.3f,"
485 " startPosition=%d, stopPosition=%d)", fileName, loop,
486 format, volumeScaling, startPosition, stopPosition);
487
488 if (_filePlaying)
489 {
490 _engineStatisticsPtr->SetLastError(
491 VE_ALREADY_PLAYING, kTraceWarning,
492 "StartPlayingFileAsMicrophone() is already playing");
493 return 0;
494 }
495
tommi31fc21f2016-01-21 10:37:37 -0800496 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000497
498 // Destroy the old instance
499 if (_filePlayerPtr)
500 {
501 _filePlayerPtr->RegisterModuleFileCallback(NULL);
502 FilePlayer::DestroyFilePlayer(_filePlayerPtr);
503 _filePlayerPtr = NULL;
504 }
505
506 // Dynamically create the instance
507 _filePlayerPtr
508 = FilePlayer::CreateFilePlayer(_filePlayerId,
509 (const FileFormats) format);
510
511 if (_filePlayerPtr == NULL)
512 {
513 _engineStatisticsPtr->SetLastError(
514 VE_INVALID_ARGUMENT, kTraceError,
515 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
516 return -1;
517 }
518
519 const uint32_t notificationTime(0);
520
521 if (_filePlayerPtr->StartPlayingFile(
522 fileName,
523 loop,
524 startPosition,
525 volumeScaling,
526 notificationTime,
527 stopPosition,
528 (const CodecInst*) codecInst) != 0)
529 {
530 _engineStatisticsPtr->SetLastError(
531 VE_BAD_FILE, kTraceError,
532 "StartPlayingFile() failed to start file playout");
533 _filePlayerPtr->StopPlayingFile();
534 FilePlayer::DestroyFilePlayer(_filePlayerPtr);
535 _filePlayerPtr = NULL;
536 return -1;
537 }
538
539 _filePlayerPtr->RegisterModuleFileCallback(this);
540 _filePlaying = true;
541
542 return 0;
543}
544
545int TransmitMixer::StartPlayingFileAsMicrophone(InStream* stream,
546 FileFormats format,
547 int startPosition,
548 float volumeScaling,
549 int stopPosition,
550 const CodecInst* codecInst)
551{
552 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
553 "TransmitMixer::StartPlayingFileAsMicrophone(format=%d,"
554 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
555 format, volumeScaling, startPosition, stopPosition);
556
557 if (stream == NULL)
558 {
559 _engineStatisticsPtr->SetLastError(
560 VE_BAD_FILE, kTraceError,
561 "StartPlayingFileAsMicrophone() NULL as input stream");
562 return -1;
563 }
564
565 if (_filePlaying)
566 {
567 _engineStatisticsPtr->SetLastError(
568 VE_ALREADY_PLAYING, kTraceWarning,
569 "StartPlayingFileAsMicrophone() is already playing");
570 return 0;
571 }
572
tommi31fc21f2016-01-21 10:37:37 -0800573 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000574
575 // Destroy the old instance
576 if (_filePlayerPtr)
577 {
578 _filePlayerPtr->RegisterModuleFileCallback(NULL);
579 FilePlayer::DestroyFilePlayer(_filePlayerPtr);
580 _filePlayerPtr = NULL;
581 }
582
583 // Dynamically create the instance
584 _filePlayerPtr
585 = FilePlayer::CreateFilePlayer(_filePlayerId,
586 (const FileFormats) format);
587
588 if (_filePlayerPtr == NULL)
589 {
590 _engineStatisticsPtr->SetLastError(
591 VE_INVALID_ARGUMENT, kTraceWarning,
592 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
593 return -1;
594 }
595
596 const uint32_t notificationTime(0);
597
598 if (_filePlayerPtr->StartPlayingFile(
599 (InStream&) *stream,
600 startPosition,
601 volumeScaling,
602 notificationTime,
603 stopPosition,
604 (const CodecInst*) codecInst) != 0)
605 {
606 _engineStatisticsPtr->SetLastError(
607 VE_BAD_FILE, kTraceError,
608 "StartPlayingFile() failed to start file playout");
609 _filePlayerPtr->StopPlayingFile();
610 FilePlayer::DestroyFilePlayer(_filePlayerPtr);
611 _filePlayerPtr = NULL;
612 return -1;
613 }
614 _filePlayerPtr->RegisterModuleFileCallback(this);
615 _filePlaying = true;
616
617 return 0;
618}
619
620int TransmitMixer::StopPlayingFileAsMicrophone()
621{
622 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
623 "TransmitMixer::StopPlayingFileAsMicrophone()");
624
625 if (!_filePlaying)
626 {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000627 return 0;
628 }
629
tommi31fc21f2016-01-21 10:37:37 -0800630 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000631
632 if (_filePlayerPtr->StopPlayingFile() != 0)
633 {
634 _engineStatisticsPtr->SetLastError(
635 VE_CANNOT_STOP_PLAYOUT, kTraceError,
636 "StopPlayingFile() couldnot stop playing file");
637 return -1;
638 }
639
640 _filePlayerPtr->RegisterModuleFileCallback(NULL);
641 FilePlayer::DestroyFilePlayer(_filePlayerPtr);
642 _filePlayerPtr = NULL;
643 _filePlaying = false;
644
645 return 0;
646}
647
648int TransmitMixer::IsPlayingFileAsMicrophone() const
649{
650 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
651 "TransmitMixer::IsPlayingFileAsMicrophone()");
652 return _filePlaying;
653}
654
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000655int TransmitMixer::StartRecordingMicrophone(const char* fileName,
656 const CodecInst* codecInst)
657{
658 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
659 "TransmitMixer::StartRecordingMicrophone(fileName=%s)",
660 fileName);
661
tommi31fc21f2016-01-21 10:37:37 -0800662 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000663
664 if (_fileRecording)
665 {
666 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
667 "StartRecordingMicrophone() is already recording");
668 return 0;
669 }
670
671 FileFormats format;
672 const uint32_t notificationTime(0); // Not supported in VoE
673 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
674
Peter Kasting69558702016-01-12 16:26:35 -0800675 if (codecInst != NULL && codecInst->channels > 2)
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000676 {
677 _engineStatisticsPtr->SetLastError(
678 VE_BAD_ARGUMENT, kTraceError,
679 "StartRecordingMicrophone() invalid compression");
680 return (-1);
681 }
682 if (codecInst == NULL)
683 {
684 format = kFileFormatPcm16kHzFile;
685 codecInst = &dummyCodec;
686 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
687 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
688 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
689 {
690 format = kFileFormatWavFile;
691 } else
692 {
693 format = kFileFormatCompressedFile;
694 }
695
696 // Destroy the old instance
697 if (_fileRecorderPtr)
698 {
699 _fileRecorderPtr->RegisterModuleFileCallback(NULL);
700 FileRecorder::DestroyFileRecorder(_fileRecorderPtr);
701 _fileRecorderPtr = NULL;
702 }
703
704 _fileRecorderPtr =
705 FileRecorder::CreateFileRecorder(_fileRecorderId,
706 (const FileFormats) format);
707 if (_fileRecorderPtr == NULL)
708 {
709 _engineStatisticsPtr->SetLastError(
710 VE_INVALID_ARGUMENT, kTraceError,
711 "StartRecordingMicrophone() fileRecorder format isnot correct");
712 return -1;
713 }
714
715 if (_fileRecorderPtr->StartRecordingAudioFile(
716 fileName,
717 (const CodecInst&) *codecInst,
718 notificationTime) != 0)
719 {
720 _engineStatisticsPtr->SetLastError(
721 VE_BAD_FILE, kTraceError,
722 "StartRecordingAudioFile() failed to start file recording");
723 _fileRecorderPtr->StopRecording();
724 FileRecorder::DestroyFileRecorder(_fileRecorderPtr);
725 _fileRecorderPtr = NULL;
726 return -1;
727 }
728 _fileRecorderPtr->RegisterModuleFileCallback(this);
729 _fileRecording = true;
730
731 return 0;
732}
733
734int TransmitMixer::StartRecordingMicrophone(OutStream* stream,
735 const CodecInst* codecInst)
736{
737 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
738 "TransmitMixer::StartRecordingMicrophone()");
739
tommi31fc21f2016-01-21 10:37:37 -0800740 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000741
742 if (_fileRecording)
743 {
744 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
745 "StartRecordingMicrophone() is already recording");
746 return 0;
747 }
748
749 FileFormats format;
750 const uint32_t notificationTime(0); // Not supported in VoE
751 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
752
753 if (codecInst != NULL && codecInst->channels != 1)
754 {
755 _engineStatisticsPtr->SetLastError(
756 VE_BAD_ARGUMENT, kTraceError,
757 "StartRecordingMicrophone() invalid compression");
758 return (-1);
759 }
760 if (codecInst == NULL)
761 {
762 format = kFileFormatPcm16kHzFile;
763 codecInst = &dummyCodec;
764 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
765 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
766 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
767 {
768 format = kFileFormatWavFile;
769 } else
770 {
771 format = kFileFormatCompressedFile;
772 }
773
774 // Destroy the old instance
775 if (_fileRecorderPtr)
776 {
777 _fileRecorderPtr->RegisterModuleFileCallback(NULL);
778 FileRecorder::DestroyFileRecorder(_fileRecorderPtr);
779 _fileRecorderPtr = NULL;
780 }
781
782 _fileRecorderPtr =
783 FileRecorder::CreateFileRecorder(_fileRecorderId,
784 (const FileFormats) format);
785 if (_fileRecorderPtr == NULL)
786 {
787 _engineStatisticsPtr->SetLastError(
788 VE_INVALID_ARGUMENT, kTraceError,
789 "StartRecordingMicrophone() fileRecorder format isnot correct");
790 return -1;
791 }
792
793 if (_fileRecorderPtr->StartRecordingAudioFile(*stream,
794 *codecInst,
795 notificationTime) != 0)
796 {
797 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
798 "StartRecordingAudioFile() failed to start file recording");
799 _fileRecorderPtr->StopRecording();
800 FileRecorder::DestroyFileRecorder(_fileRecorderPtr);
801 _fileRecorderPtr = NULL;
802 return -1;
803 }
804
805 _fileRecorderPtr->RegisterModuleFileCallback(this);
806 _fileRecording = true;
807
808 return 0;
809}
810
811
812int TransmitMixer::StopRecordingMicrophone()
813{
814 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
815 "TransmitMixer::StopRecordingMicrophone()");
816
tommi31fc21f2016-01-21 10:37:37 -0800817 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000818
819 if (!_fileRecording)
820 {
821 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
822 "StopRecordingMicrophone() isnot recording");
823 return 0;
824 }
825
826 if (_fileRecorderPtr->StopRecording() != 0)
827 {
828 _engineStatisticsPtr->SetLastError(
829 VE_STOP_RECORDING_FAILED, kTraceError,
830 "StopRecording(), could not stop recording");
831 return -1;
832 }
833 _fileRecorderPtr->RegisterModuleFileCallback(NULL);
834 FileRecorder::DestroyFileRecorder(_fileRecorderPtr);
835 _fileRecorderPtr = NULL;
836 _fileRecording = false;
837
838 return 0;
839}
840
841int TransmitMixer::StartRecordingCall(const char* fileName,
842 const CodecInst* codecInst)
843{
844 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
845 "TransmitMixer::StartRecordingCall(fileName=%s)", fileName);
846
847 if (_fileCallRecording)
848 {
849 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
850 "StartRecordingCall() is already recording");
851 return 0;
852 }
853
854 FileFormats format;
855 const uint32_t notificationTime(0); // Not supported in VoE
856 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
857
858 if (codecInst != NULL && codecInst->channels != 1)
859 {
860 _engineStatisticsPtr->SetLastError(
861 VE_BAD_ARGUMENT, kTraceError,
862 "StartRecordingCall() invalid compression");
863 return (-1);
864 }
865 if (codecInst == NULL)
866 {
867 format = kFileFormatPcm16kHzFile;
868 codecInst = &dummyCodec;
869 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
870 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
871 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
872 {
873 format = kFileFormatWavFile;
874 } else
875 {
876 format = kFileFormatCompressedFile;
877 }
878
tommi31fc21f2016-01-21 10:37:37 -0800879 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000880
881 // Destroy the old instance
882 if (_fileCallRecorderPtr)
883 {
884 _fileCallRecorderPtr->RegisterModuleFileCallback(NULL);
885 FileRecorder::DestroyFileRecorder(_fileCallRecorderPtr);
886 _fileCallRecorderPtr = NULL;
887 }
888
889 _fileCallRecorderPtr
890 = FileRecorder::CreateFileRecorder(_fileCallRecorderId,
891 (const FileFormats) format);
892 if (_fileCallRecorderPtr == NULL)
893 {
894 _engineStatisticsPtr->SetLastError(
895 VE_INVALID_ARGUMENT, kTraceError,
896 "StartRecordingCall() fileRecorder format isnot correct");
897 return -1;
898 }
899
900 if (_fileCallRecorderPtr->StartRecordingAudioFile(
901 fileName,
902 (const CodecInst&) *codecInst,
903 notificationTime) != 0)
904 {
905 _engineStatisticsPtr->SetLastError(
906 VE_BAD_FILE, kTraceError,
907 "StartRecordingAudioFile() failed to start file recording");
908 _fileCallRecorderPtr->StopRecording();
909 FileRecorder::DestroyFileRecorder(_fileCallRecorderPtr);
910 _fileCallRecorderPtr = NULL;
911 return -1;
912 }
913 _fileCallRecorderPtr->RegisterModuleFileCallback(this);
914 _fileCallRecording = true;
915
916 return 0;
917}
918
919int TransmitMixer::StartRecordingCall(OutStream* stream,
920 const CodecInst* codecInst)
921{
922 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
923 "TransmitMixer::StartRecordingCall()");
924
925 if (_fileCallRecording)
926 {
927 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
928 "StartRecordingCall() is already recording");
929 return 0;
930 }
931
932 FileFormats format;
933 const uint32_t notificationTime(0); // Not supported in VoE
934 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
935
936 if (codecInst != NULL && codecInst->channels != 1)
937 {
938 _engineStatisticsPtr->SetLastError(
939 VE_BAD_ARGUMENT, kTraceError,
940 "StartRecordingCall() invalid compression");
941 return (-1);
942 }
943 if (codecInst == NULL)
944 {
945 format = kFileFormatPcm16kHzFile;
946 codecInst = &dummyCodec;
947 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
948 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
949 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
950 {
951 format = kFileFormatWavFile;
952 } else
953 {
954 format = kFileFormatCompressedFile;
955 }
956
tommi31fc21f2016-01-21 10:37:37 -0800957 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000958
959 // Destroy the old instance
960 if (_fileCallRecorderPtr)
961 {
962 _fileCallRecorderPtr->RegisterModuleFileCallback(NULL);
963 FileRecorder::DestroyFileRecorder(_fileCallRecorderPtr);
964 _fileCallRecorderPtr = NULL;
965 }
966
967 _fileCallRecorderPtr =
968 FileRecorder::CreateFileRecorder(_fileCallRecorderId,
969 (const FileFormats) format);
970 if (_fileCallRecorderPtr == NULL)
971 {
972 _engineStatisticsPtr->SetLastError(
973 VE_INVALID_ARGUMENT, kTraceError,
974 "StartRecordingCall() fileRecorder format isnot correct");
975 return -1;
976 }
977
978 if (_fileCallRecorderPtr->StartRecordingAudioFile(*stream,
979 *codecInst,
980 notificationTime) != 0)
981 {
982 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
983 "StartRecordingAudioFile() failed to start file recording");
984 _fileCallRecorderPtr->StopRecording();
985 FileRecorder::DestroyFileRecorder(_fileCallRecorderPtr);
986 _fileCallRecorderPtr = NULL;
987 return -1;
988 }
989
990 _fileCallRecorderPtr->RegisterModuleFileCallback(this);
991 _fileCallRecording = true;
992
993 return 0;
994}
995
996int TransmitMixer::StopRecordingCall()
997{
998 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
999 "TransmitMixer::StopRecordingCall()");
1000
1001 if (!_fileCallRecording)
1002 {
1003 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
1004 "StopRecordingCall() file isnot recording");
1005 return -1;
1006 }
1007
tommi31fc21f2016-01-21 10:37:37 -08001008 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001009
1010 if (_fileCallRecorderPtr->StopRecording() != 0)
1011 {
1012 _engineStatisticsPtr->SetLastError(
1013 VE_STOP_RECORDING_FAILED, kTraceError,
1014 "StopRecording(), could not stop recording");
1015 return -1;
1016 }
1017
1018 _fileCallRecorderPtr->RegisterModuleFileCallback(NULL);
1019 FileRecorder::DestroyFileRecorder(_fileCallRecorderPtr);
1020 _fileCallRecorderPtr = NULL;
1021 _fileCallRecording = false;
1022
1023 return 0;
1024}
1025
1026void
1027TransmitMixer::SetMixWithMicStatus(bool mix)
1028{
1029 _mixFileWithMicrophone = mix;
1030}
1031
1032int TransmitMixer::RegisterExternalMediaProcessing(
1033 VoEMediaProcess* object,
1034 ProcessingTypes type) {
1035 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
1036 "TransmitMixer::RegisterExternalMediaProcessing()");
1037
tommi31fc21f2016-01-21 10:37:37 -08001038 rtc::CritScope cs(&_callbackCritSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001039 if (!object) {
1040 return -1;
1041 }
1042
1043 // Store the callback object according to the processing type.
1044 if (type == kRecordingAllChannelsMixed) {
1045 external_postproc_ptr_ = object;
1046 } else if (type == kRecordingPreprocessing) {
1047 external_preproc_ptr_ = object;
1048 } else {
1049 return -1;
1050 }
1051 return 0;
1052}
1053
1054int TransmitMixer::DeRegisterExternalMediaProcessing(ProcessingTypes type) {
1055 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
1056 "TransmitMixer::DeRegisterExternalMediaProcessing()");
1057
tommi31fc21f2016-01-21 10:37:37 -08001058 rtc::CritScope cs(&_callbackCritSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001059 if (type == kRecordingAllChannelsMixed) {
1060 external_postproc_ptr_ = NULL;
1061 } else if (type == kRecordingPreprocessing) {
1062 external_preproc_ptr_ = NULL;
1063 } else {
1064 return -1;
1065 }
1066 return 0;
1067}
1068
1069int
1070TransmitMixer::SetMute(bool enable)
1071{
1072 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
1073 "TransmitMixer::SetMute(enable=%d)", enable);
1074 _mute = enable;
1075 return 0;
1076}
1077
1078bool
1079TransmitMixer::Mute() const
1080{
1081 return _mute;
1082}
1083
1084int8_t TransmitMixer::AudioLevel() const
1085{
1086 // Speech + file level [0,9]
1087 return _audioLevel.Level();
1088}
1089
1090int16_t TransmitMixer::AudioLevelFullRange() const
1091{
1092 // Speech + file level [0,32767]
1093 return _audioLevel.LevelFullRange();
1094}
1095
1096bool TransmitMixer::IsRecordingCall()
1097{
1098 return _fileCallRecording;
1099}
1100
1101bool TransmitMixer::IsRecordingMic()
1102{
tommi31fc21f2016-01-21 10:37:37 -08001103 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001104 return _fileRecording;
1105}
1106
1107void TransmitMixer::GenerateAudioFrame(const int16_t* audio,
Peter Kastingdce40cf2015-08-24 14:52:23 -07001108 size_t samples_per_channel,
Peter Kasting69558702016-01-12 16:26:35 -08001109 size_t num_channels,
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001110 int sample_rate_hz) {
1111 int codec_rate;
Peter Kasting69558702016-01-12 16:26:35 -08001112 size_t num_codec_channels;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001113 GetSendCodecInfo(&codec_rate, &num_codec_channels);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001114 stereo_codec_ = num_codec_channels == 2;
1115
Alejandro Luebscdfe20b2015-09-23 12:49:12 -07001116 // We want to process at the lowest rate possible without losing information.
1117 // Choose the lowest native rate at least equal to the input and codec rates.
1118 const int min_processing_rate = std::min(sample_rate_hz, codec_rate);
1119 for (size_t i = 0; i < AudioProcessing::kNumNativeSampleRates; ++i) {
1120 _audioFrame.sample_rate_hz_ = AudioProcessing::kNativeSampleRatesHz[i];
1121 if (_audioFrame.sample_rate_hz_ >= min_processing_rate) {
1122 break;
1123 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001124 }
Alejandro Luebscdfe20b2015-09-23 12:49:12 -07001125 _audioFrame.num_channels_ = std::min(num_channels, num_codec_channels);
1126 RemixAndResample(audio, samples_per_channel, num_channels, sample_rate_hz,
1127 &resampler_, &_audioFrame);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001128}
1129
1130int32_t TransmitMixer::RecordAudioToFile(
1131 uint32_t mixingFrequency)
1132{
tommi31fc21f2016-01-21 10:37:37 -08001133 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001134 if (_fileRecorderPtr == NULL)
1135 {
1136 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
1137 "TransmitMixer::RecordAudioToFile() filerecorder doesnot"
1138 "exist");
1139 return -1;
1140 }
1141
1142 if (_fileRecorderPtr->RecordAudioToFile(_audioFrame) != 0)
1143 {
1144 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
1145 "TransmitMixer::RecordAudioToFile() file recording"
1146 "failed");
1147 return -1;
1148 }
1149
1150 return 0;
1151}
1152
1153int32_t TransmitMixer::MixOrReplaceAudioWithFile(
1154 int mixingFrequency)
1155{
kwibergb7f89d62016-02-17 10:04:18 -08001156 std::unique_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001157
Peter Kastingdce40cf2015-08-24 14:52:23 -07001158 size_t fileSamples(0);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001159 {
tommi31fc21f2016-01-21 10:37:37 -08001160 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001161 if (_filePlayerPtr == NULL)
1162 {
1163 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1164 VoEId(_instanceId, -1),
1165 "TransmitMixer::MixOrReplaceAudioWithFile()"
1166 "fileplayer doesnot exist");
1167 return -1;
1168 }
1169
1170 if (_filePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
1171 fileSamples,
1172 mixingFrequency) == -1)
1173 {
1174 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
1175 "TransmitMixer::MixOrReplaceAudioWithFile() file"
1176 " mixing failed");
1177 return -1;
1178 }
1179 }
1180
1181 assert(_audioFrame.samples_per_channel_ == fileSamples);
1182
1183 if (_mixFileWithMicrophone)
1184 {
1185 // Currently file stream is always mono.
1186 // TODO(xians): Change the code when FilePlayer supports real stereo.
1187 MixWithSat(_audioFrame.data_,
1188 _audioFrame.num_channels_,
1189 fileBuffer.get(),
1190 1,
1191 fileSamples);
1192 } else
1193 {
1194 // Replace ACM audio with file.
1195 // Currently file stream is always mono.
1196 // TODO(xians): Change the code when FilePlayer supports real stereo.
1197 _audioFrame.UpdateFrame(-1,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00001198 0xFFFFFFFF,
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001199 fileBuffer.get(),
1200 fileSamples,
1201 mixingFrequency,
1202 AudioFrame::kNormalSpeech,
1203 AudioFrame::kVadUnknown,
1204 1);
1205 }
1206 return 0;
1207}
1208
1209void TransmitMixer::ProcessAudio(int delay_ms, int clock_drift,
1210 int current_mic_level, bool key_pressed) {
1211 if (audioproc_->set_stream_delay_ms(delay_ms) != 0) {
pbosad856222015-11-27 09:48:36 -08001212 // Silently ignore this failure to avoid flooding the logs.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001213 }
1214
1215 GainControl* agc = audioproc_->gain_control();
1216 if (agc->set_stream_analog_level(current_mic_level) != 0) {
pbosad856222015-11-27 09:48:36 -08001217 LOG(LS_ERROR) << "set_stream_analog_level failed: current_mic_level = "
1218 << current_mic_level;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001219 assert(false);
1220 }
1221
1222 EchoCancellation* aec = audioproc_->echo_cancellation();
1223 if (aec->is_drift_compensation_enabled()) {
1224 aec->set_stream_drift_samples(clock_drift);
1225 }
1226
1227 audioproc_->set_stream_key_pressed(key_pressed);
1228
1229 int err = audioproc_->ProcessStream(&_audioFrame);
1230 if (err != 0) {
1231 LOG(LS_ERROR) << "ProcessStream() error: " << err;
1232 assert(false);
1233 }
1234
1235 // Store new capture level. Only updated when analog AGC is enabled.
1236 _captureLevel = agc->stream_analog_level();
1237
tommi31fc21f2016-01-21 10:37:37 -08001238 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001239 // Triggers a callback in OnPeriodicProcess().
1240 _saturationWarning |= agc->stream_is_saturated();
1241}
1242
1243#ifdef WEBRTC_VOICE_ENGINE_TYPING_DETECTION
1244void TransmitMixer::TypingDetection(bool keyPressed)
1245{
1246 // We let the VAD determine if we're using this feature or not.
1247 if (_audioFrame.vad_activity_ == AudioFrame::kVadUnknown) {
1248 return;
1249 }
1250
1251 bool vadActive = _audioFrame.vad_activity_ == AudioFrame::kVadActive;
1252 if (_typingDetection.Process(keyPressed, vadActive)) {
tommi31fc21f2016-01-21 10:37:37 -08001253 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001254 _typingNoiseWarningPending = true;
1255 _typingNoiseDetected = true;
1256 } else {
tommi31fc21f2016-01-21 10:37:37 -08001257 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001258 // If there is already a warning pending, do not change the state.
1259 // Otherwise set a warning pending if last callback was for noise detected.
1260 if (!_typingNoiseWarningPending && _typingNoiseDetected) {
1261 _typingNoiseWarningPending = true;
1262 _typingNoiseDetected = false;
1263 }
1264 }
1265}
1266#endif
1267
1268int TransmitMixer::GetMixingFrequency()
1269{
1270 assert(_audioFrame.sample_rate_hz_ != 0);
1271 return _audioFrame.sample_rate_hz_;
1272}
1273
1274#ifdef WEBRTC_VOICE_ENGINE_TYPING_DETECTION
1275int TransmitMixer::TimeSinceLastTyping(int &seconds)
1276{
1277 // We check in VoEAudioProcessingImpl that this is only called when
1278 // typing detection is active.
1279 seconds = _typingDetection.TimeSinceLastDetectionInSeconds();
1280 return 0;
1281}
1282#endif
1283
1284#ifdef WEBRTC_VOICE_ENGINE_TYPING_DETECTION
1285int TransmitMixer::SetTypingDetectionParameters(int timeWindow,
1286 int costPerTyping,
1287 int reportingThreshold,
1288 int penaltyDecay,
1289 int typeEventDelay)
1290{
1291 _typingDetection.SetParameters(timeWindow,
1292 costPerTyping,
1293 reportingThreshold,
1294 penaltyDecay,
1295 typeEventDelay,
1296 0);
1297 return 0;
1298}
1299#endif
1300
1301void TransmitMixer::EnableStereoChannelSwapping(bool enable) {
1302 swap_stereo_channels_ = enable;
1303}
1304
1305bool TransmitMixer::IsStereoChannelSwappingEnabled() {
1306 return swap_stereo_channels_;
1307}
1308
1309} // namespace voe
1310} // namespace webrtc