blob: 07b47ec48e71a8a74e1080fe82888ee5c314a8f6 [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"
tommidea489f2017-03-03 03:20:24 -080017#include "webrtc/base/location.h"
pbosad856222015-11-27 09:48:36 -080018#include "webrtc/base/logging.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010019#include "webrtc/system_wrappers/include/event_wrapper.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010020#include "webrtc/system_wrappers/include/trace.h"
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000021#include "webrtc/voice_engine/channel.h"
22#include "webrtc/voice_engine/channel_manager.h"
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000023#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
tommiba08a142017-02-28 08:25:11 -080030#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000031// TODO(ajm): The thread safety of this is dubious...
tommiba08a142017-02-28 08:25:11 -080032void TransmitMixer::OnPeriodicProcess()
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000033{
34 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
35 "TransmitMixer::OnPeriodicProcess()");
36
solenberg302c9782015-11-24 06:28:22 -080037 bool send_typing_noise_warning = false;
38 bool typing_noise_detected = false;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000039 {
tommi31fc21f2016-01-21 10:37:37 -080040 rtc::CritScope cs(&_critSect);
solenberg302c9782015-11-24 06:28:22 -080041 if (_typingNoiseWarningPending) {
42 send_typing_noise_warning = true;
43 typing_noise_detected = _typingNoiseDetected;
44 _typingNoiseWarningPending = false;
45 }
46 }
47 if (send_typing_noise_warning) {
tommi31fc21f2016-01-21 10:37:37 -080048 rtc::CritScope cs(&_callbackCritSect);
solenberg302c9782015-11-24 06:28:22 -080049 if (_voiceEngineObserverPtr) {
50 if (typing_noise_detected) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000051 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 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000066 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000067}
tommiba08a142017-02-28 08:25:11 -080068#endif // WEBRTC_VOICE_ENGINE_TYPING_DETECTION
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000069
70void TransmitMixer::PlayNotification(int32_t id,
71 uint32_t durationMs)
72{
73 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
74 "TransmitMixer::PlayNotification(id=%d, durationMs=%d)",
75 id, durationMs);
76
77 // Not implement yet
78}
79
80void TransmitMixer::RecordNotification(int32_t id,
81 uint32_t durationMs)
82{
83 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1),
84 "TransmitMixer::RecordNotification(id=%d, durationMs=%d)",
85 id, durationMs);
86
87 // Not implement yet
88}
89
90void TransmitMixer::PlayFileEnded(int32_t id)
91{
92 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
93 "TransmitMixer::PlayFileEnded(id=%d)", id);
94
95 assert(id == _filePlayerId);
96
tommi31fc21f2016-01-21 10:37:37 -080097 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000098
99 _filePlaying = false;
100 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1),
101 "TransmitMixer::PlayFileEnded() =>"
102 "file player module is shutdown");
103}
104
105void
106TransmitMixer::RecordFileEnded(int32_t id)
107{
108 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
109 "TransmitMixer::RecordFileEnded(id=%d)", id);
110
111 if (id == _fileRecorderId)
112 {
tommi31fc21f2016-01-21 10:37:37 -0800113 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000114 _fileRecording = false;
115 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1),
116 "TransmitMixer::RecordFileEnded() => fileRecorder module"
117 "is shutdown");
118 } else if (id == _fileCallRecorderId)
119 {
tommi31fc21f2016-01-21 10:37:37 -0800120 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000121 _fileCallRecording = false;
122 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1),
123 "TransmitMixer::RecordFileEnded() => fileCallRecorder"
124 "module is shutdown");
125 }
126}
127
128int32_t
129TransmitMixer::Create(TransmitMixer*& mixer, uint32_t instanceId)
130{
131 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, -1),
132 "TransmitMixer::Create(instanceId=%d)", instanceId);
133 mixer = new TransmitMixer(instanceId);
134 if (mixer == NULL)
135 {
136 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, -1),
137 "TransmitMixer::Create() unable to allocate memory"
138 "for mixer");
139 return -1;
140 }
141 return 0;
142}
143
144void
145TransmitMixer::Destroy(TransmitMixer*& mixer)
146{
147 if (mixer)
148 {
149 delete mixer;
150 mixer = NULL;
151 }
152}
153
154TransmitMixer::TransmitMixer(uint32_t instanceId) :
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000155 // Avoid conflict with other channels by adding 1024 - 1026,
156 // won't use as much as 1024 channels.
157 _filePlayerId(instanceId + 1024),
158 _fileRecorderId(instanceId + 1025),
159 _fileCallRecorderId(instanceId + 1026),
tommiba08a142017-02-28 08:25:11 -0800160#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
161 _monitorModule(this),
162#endif
solenberg76377c52017-02-21 00:54:31 -0800163 _instanceId(instanceId)
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000164{
165 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1),
166 "TransmitMixer::TransmitMixer() - ctor");
167}
168
169TransmitMixer::~TransmitMixer()
170{
171 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1),
172 "TransmitMixer::~TransmitMixer() - dtor");
tommiba08a142017-02-28 08:25:11 -0800173#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000174 if (_processThreadPtr)
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000175 _processThreadPtr->DeRegisterModule(&_monitorModule);
tommiba08a142017-02-28 08:25:11 -0800176#endif
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000177 {
tommi31fc21f2016-01-21 10:37:37 -0800178 rtc::CritScope cs(&_critSect);
kwiberg5a25d952016-08-17 07:31:12 -0700179 if (file_recorder_) {
180 file_recorder_->RegisterModuleFileCallback(NULL);
181 file_recorder_->StopRecording();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000182 }
kwiberg5a25d952016-08-17 07:31:12 -0700183 if (file_call_recorder_) {
184 file_call_recorder_->RegisterModuleFileCallback(NULL);
185 file_call_recorder_->StopRecording();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000186 }
kwiberg5a25d952016-08-17 07:31:12 -0700187 if (file_player_) {
188 file_player_->RegisterModuleFileCallback(NULL);
189 file_player_->StopPlayingFile();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000190 }
191 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000192}
193
194int32_t
195TransmitMixer::SetEngineInformation(ProcessThread& processThread,
196 Statistics& engineStatistics,
197 ChannelManager& channelManager)
198{
199 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
200 "TransmitMixer::SetEngineInformation()");
201
202 _processThreadPtr = &processThread;
203 _engineStatisticsPtr = &engineStatistics;
204 _channelManagerPtr = &channelManager;
205
tommiba08a142017-02-28 08:25:11 -0800206#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
tommidea489f2017-03-03 03:20:24 -0800207 _processThreadPtr->RegisterModule(&_monitorModule, RTC_FROM_HERE);
tommiba08a142017-02-28 08:25:11 -0800208#endif
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000209 return 0;
210}
211
212int32_t
213TransmitMixer::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
214{
215 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
216 "TransmitMixer::RegisterVoiceEngineObserver()");
tommi31fc21f2016-01-21 10:37:37 -0800217 rtc::CritScope cs(&_callbackCritSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000218
219 if (_voiceEngineObserverPtr)
220 {
221 _engineStatisticsPtr->SetLastError(
222 VE_INVALID_OPERATION, kTraceError,
223 "RegisterVoiceEngineObserver() observer already enabled");
224 return -1;
225 }
226 _voiceEngineObserverPtr = &observer;
227 return 0;
228}
229
230int32_t
231TransmitMixer::SetAudioProcessingModule(AudioProcessing* audioProcessingModule)
232{
233 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
234 "TransmitMixer::SetAudioProcessingModule("
235 "audioProcessingModule=0x%x)",
236 audioProcessingModule);
237 audioproc_ = audioProcessingModule;
238 return 0;
239}
240
Peter Kasting69558702016-01-12 16:26:35 -0800241void TransmitMixer::GetSendCodecInfo(int* max_sample_rate,
242 size_t* max_channels) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000243 *max_sample_rate = 8000;
244 *max_channels = 1;
245 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
246 it.Increment()) {
247 Channel* channel = it.GetChannel();
248 if (channel->Sending()) {
249 CodecInst codec;
250 channel->GetSendCodec(codec);
251 *max_sample_rate = std::max(*max_sample_rate, codec.plfreq);
252 *max_channels = std::max(*max_channels, codec.channels);
253 }
254 }
255}
256
257int32_t
258TransmitMixer::PrepareDemux(const void* audioSamples,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700259 size_t nSamples,
Peter Kasting69558702016-01-12 16:26:35 -0800260 size_t nChannels,
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000261 uint32_t samplesPerSec,
262 uint16_t totalDelayMS,
263 int32_t clockDrift,
264 uint16_t currentMicLevel,
265 bool keyPressed)
266{
267 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
Peter Kastingdce40cf2015-08-24 14:52:23 -0700268 "TransmitMixer::PrepareDemux(nSamples=%" PRIuS ", "
Peter Kasting69558702016-01-12 16:26:35 -0800269 "nChannels=%" PRIuS ", samplesPerSec=%u, totalDelayMS=%u, "
Peter Kastingdce40cf2015-08-24 14:52:23 -0700270 "clockDrift=%d, currentMicLevel=%u)",
271 nSamples, nChannels, samplesPerSec, totalDelayMS, clockDrift,
272 currentMicLevel);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000273
274 // --- Resample input audio and create/store the initial audio frame
275 GenerateAudioFrame(static_cast<const int16_t*>(audioSamples),
276 nSamples,
277 nChannels,
278 samplesPerSec);
279
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000280 // --- Near-end audio processing.
281 ProcessAudio(totalDelayMS, clockDrift, currentMicLevel, keyPressed);
282
283 if (swap_stereo_channels_ && stereo_codec_)
284 // Only bother swapping if we're using a stereo codec.
285 AudioFrameOperations::SwapStereoChannels(&_audioFrame);
286
287 // --- Annoying typing detection (utilizes the APM/VAD decision)
henrik.lundinf00082d2016-12-05 02:22:12 -0800288#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000289 TypingDetection(keyPressed);
290#endif
291
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000292 // --- Mix with file (does not affect the mixing frequency)
293 if (_filePlaying)
294 {
295 MixOrReplaceAudioWithFile(_audioFrame.sample_rate_hz_);
296 }
297
298 // --- Record to file
299 bool file_recording = false;
300 {
tommi31fc21f2016-01-21 10:37:37 -0800301 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000302 file_recording = _fileRecording;
303 }
304 if (file_recording)
305 {
306 RecordAudioToFile(_audioFrame.sample_rate_hz_);
307 }
308
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000309 // --- Measure audio level of speech after all processing.
310 _audioLevel.ComputeLevel(_audioFrame);
311 return 0;
312}
313
314int32_t
315TransmitMixer::DemuxAndMix()
316{
317 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
318 "TransmitMixer::DemuxAndMix()");
319
320 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
321 it.Increment())
322 {
323 Channel* channelPtr = it.GetChannel();
henrika@webrtc.org66803482014-04-17 10:45:01 +0000324 if (channelPtr->Sending())
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000325 {
326 // Demultiplex makes a copy of its input.
327 channelPtr->Demultiplex(_audioFrame);
328 channelPtr->PrepareEncodeAndSend(_audioFrame.sample_rate_hz_);
329 }
330 }
331 return 0;
332}
333
334void TransmitMixer::DemuxAndMix(const int voe_channels[],
Peter Kasting69558702016-01-12 16:26:35 -0800335 size_t number_of_voe_channels) {
336 for (size_t i = 0; i < number_of_voe_channels; ++i) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000337 voe::ChannelOwner ch = _channelManagerPtr->GetChannel(voe_channels[i]);
338 voe::Channel* channel_ptr = ch.channel();
339 if (channel_ptr) {
henrika@webrtc.org66803482014-04-17 10:45:01 +0000340 if (channel_ptr->Sending()) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000341 // Demultiplex makes a copy of its input.
342 channel_ptr->Demultiplex(_audioFrame);
343 channel_ptr->PrepareEncodeAndSend(_audioFrame.sample_rate_hz_);
344 }
345 }
346 }
347}
348
349int32_t
350TransmitMixer::EncodeAndSend()
351{
352 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
353 "TransmitMixer::EncodeAndSend()");
354
355 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
356 it.Increment())
357 {
358 Channel* channelPtr = it.GetChannel();
henrika@webrtc.org66803482014-04-17 10:45:01 +0000359 if (channelPtr->Sending())
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000360 {
361 channelPtr->EncodeAndSend();
362 }
363 }
364 return 0;
365}
366
367void TransmitMixer::EncodeAndSend(const int voe_channels[],
Peter Kasting69558702016-01-12 16:26:35 -0800368 size_t number_of_voe_channels) {
369 for (size_t i = 0; i < number_of_voe_channels; ++i) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000370 voe::ChannelOwner ch = _channelManagerPtr->GetChannel(voe_channels[i]);
371 voe::Channel* channel_ptr = ch.channel();
henrika@webrtc.org66803482014-04-17 10:45:01 +0000372 if (channel_ptr && channel_ptr->Sending())
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000373 channel_ptr->EncodeAndSend();
374 }
375}
376
377uint32_t TransmitMixer::CaptureLevel() const
378{
379 return _captureLevel;
380}
381
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000382int32_t
383TransmitMixer::StopSend()
384{
385 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
386 "TransmitMixer::StopSend()");
387 _audioLevel.Clear();
388 return 0;
389}
390
391int TransmitMixer::StartPlayingFileAsMicrophone(const char* fileName,
392 bool loop,
393 FileFormats format,
394 int startPosition,
395 float volumeScaling,
396 int stopPosition,
397 const CodecInst* codecInst)
398{
399 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
400 "TransmitMixer::StartPlayingFileAsMicrophone("
401 "fileNameUTF8[]=%s,loop=%d, format=%d, volumeScaling=%5.3f,"
402 " startPosition=%d, stopPosition=%d)", fileName, loop,
403 format, volumeScaling, startPosition, stopPosition);
404
405 if (_filePlaying)
406 {
407 _engineStatisticsPtr->SetLastError(
408 VE_ALREADY_PLAYING, kTraceWarning,
409 "StartPlayingFileAsMicrophone() is already playing");
410 return 0;
411 }
412
tommi31fc21f2016-01-21 10:37:37 -0800413 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000414
415 // Destroy the old instance
kwiberg5a25d952016-08-17 07:31:12 -0700416 if (file_player_) {
417 file_player_->RegisterModuleFileCallback(NULL);
418 file_player_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000419 }
420
421 // Dynamically create the instance
kwiberg5a25d952016-08-17 07:31:12 -0700422 file_player_ =
kwiberg5b356f42016-09-08 04:32:33 -0700423 FilePlayer::CreateFilePlayer(_filePlayerId, (const FileFormats)format);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000424
kwiberg5a25d952016-08-17 07:31:12 -0700425 if (!file_player_) {
426 _engineStatisticsPtr->SetLastError(
427 VE_INVALID_ARGUMENT, kTraceError,
428 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
429 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000430 }
431
432 const uint32_t notificationTime(0);
433
kwiberg5a25d952016-08-17 07:31:12 -0700434 if (file_player_->StartPlayingFile(
435 fileName, loop, startPosition, volumeScaling, notificationTime,
436 stopPosition, (const CodecInst*)codecInst) != 0) {
437 _engineStatisticsPtr->SetLastError(
438 VE_BAD_FILE, kTraceError,
439 "StartPlayingFile() failed to start file playout");
440 file_player_->StopPlayingFile();
441 file_player_.reset();
442 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000443 }
444
kwiberg5a25d952016-08-17 07:31:12 -0700445 file_player_->RegisterModuleFileCallback(this);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000446 _filePlaying = true;
447
448 return 0;
449}
450
451int TransmitMixer::StartPlayingFileAsMicrophone(InStream* stream,
452 FileFormats format,
453 int startPosition,
454 float volumeScaling,
455 int stopPosition,
456 const CodecInst* codecInst)
457{
458 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
459 "TransmitMixer::StartPlayingFileAsMicrophone(format=%d,"
460 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
461 format, volumeScaling, startPosition, stopPosition);
462
463 if (stream == NULL)
464 {
465 _engineStatisticsPtr->SetLastError(
466 VE_BAD_FILE, kTraceError,
467 "StartPlayingFileAsMicrophone() NULL as input stream");
468 return -1;
469 }
470
471 if (_filePlaying)
472 {
473 _engineStatisticsPtr->SetLastError(
474 VE_ALREADY_PLAYING, kTraceWarning,
475 "StartPlayingFileAsMicrophone() is already playing");
476 return 0;
477 }
478
tommi31fc21f2016-01-21 10:37:37 -0800479 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000480
481 // Destroy the old instance
kwiberg5a25d952016-08-17 07:31:12 -0700482 if (file_player_) {
483 file_player_->RegisterModuleFileCallback(NULL);
484 file_player_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000485 }
486
487 // Dynamically create the instance
kwiberg5a25d952016-08-17 07:31:12 -0700488 file_player_ =
kwiberg5b356f42016-09-08 04:32:33 -0700489 FilePlayer::CreateFilePlayer(_filePlayerId, (const FileFormats)format);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000490
kwiberg5a25d952016-08-17 07:31:12 -0700491 if (!file_player_) {
492 _engineStatisticsPtr->SetLastError(
493 VE_INVALID_ARGUMENT, kTraceWarning,
494 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
495 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000496 }
497
498 const uint32_t notificationTime(0);
499
kwiberg4ec01d92016-08-22 08:43:54 -0700500 if (file_player_->StartPlayingFile(stream, startPosition, volumeScaling,
501 notificationTime, stopPosition,
502 (const CodecInst*)codecInst) != 0) {
kwiberg5a25d952016-08-17 07:31:12 -0700503 _engineStatisticsPtr->SetLastError(
504 VE_BAD_FILE, kTraceError,
505 "StartPlayingFile() failed to start file playout");
506 file_player_->StopPlayingFile();
507 file_player_.reset();
508 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000509 }
kwiberg5a25d952016-08-17 07:31:12 -0700510 file_player_->RegisterModuleFileCallback(this);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000511 _filePlaying = true;
512
513 return 0;
514}
515
516int TransmitMixer::StopPlayingFileAsMicrophone()
517{
518 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
519 "TransmitMixer::StopPlayingFileAsMicrophone()");
520
521 if (!_filePlaying)
522 {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000523 return 0;
524 }
525
tommi31fc21f2016-01-21 10:37:37 -0800526 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000527
kwiberg5a25d952016-08-17 07:31:12 -0700528 if (file_player_->StopPlayingFile() != 0) {
529 _engineStatisticsPtr->SetLastError(
530 VE_CANNOT_STOP_PLAYOUT, kTraceError,
531 "StopPlayingFile() couldnot stop playing file");
532 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000533 }
534
kwiberg5a25d952016-08-17 07:31:12 -0700535 file_player_->RegisterModuleFileCallback(NULL);
536 file_player_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000537 _filePlaying = false;
538
539 return 0;
540}
541
542int TransmitMixer::IsPlayingFileAsMicrophone() const
543{
544 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
545 "TransmitMixer::IsPlayingFileAsMicrophone()");
546 return _filePlaying;
547}
548
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000549int TransmitMixer::StartRecordingMicrophone(const char* fileName,
550 const CodecInst* codecInst)
551{
552 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
553 "TransmitMixer::StartRecordingMicrophone(fileName=%s)",
554 fileName);
555
tommi31fc21f2016-01-21 10:37:37 -0800556 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000557
558 if (_fileRecording)
559 {
560 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
561 "StartRecordingMicrophone() is already recording");
562 return 0;
563 }
564
565 FileFormats format;
566 const uint32_t notificationTime(0); // Not supported in VoE
567 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
568
Peter Kasting69558702016-01-12 16:26:35 -0800569 if (codecInst != NULL && codecInst->channels > 2)
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000570 {
571 _engineStatisticsPtr->SetLastError(
572 VE_BAD_ARGUMENT, kTraceError,
573 "StartRecordingMicrophone() invalid compression");
574 return (-1);
575 }
576 if (codecInst == NULL)
577 {
578 format = kFileFormatPcm16kHzFile;
579 codecInst = &dummyCodec;
580 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
581 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
582 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
583 {
584 format = kFileFormatWavFile;
585 } else
586 {
587 format = kFileFormatCompressedFile;
588 }
589
590 // Destroy the old instance
kwiberg5a25d952016-08-17 07:31:12 -0700591 if (file_recorder_) {
592 file_recorder_->RegisterModuleFileCallback(NULL);
593 file_recorder_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000594 }
595
kwiberg5a25d952016-08-17 07:31:12 -0700596 file_recorder_ = FileRecorder::CreateFileRecorder(
597 _fileRecorderId, (const FileFormats)format);
598 if (!file_recorder_) {
599 _engineStatisticsPtr->SetLastError(
600 VE_INVALID_ARGUMENT, kTraceError,
601 "StartRecordingMicrophone() fileRecorder format isnot correct");
602 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000603 }
604
kwiberg5a25d952016-08-17 07:31:12 -0700605 if (file_recorder_->StartRecordingAudioFile(
606 fileName, (const CodecInst&)*codecInst, notificationTime) != 0) {
607 _engineStatisticsPtr->SetLastError(
608 VE_BAD_FILE, kTraceError,
609 "StartRecordingAudioFile() failed to start file recording");
610 file_recorder_->StopRecording();
611 file_recorder_.reset();
612 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000613 }
kwiberg5a25d952016-08-17 07:31:12 -0700614 file_recorder_->RegisterModuleFileCallback(this);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000615 _fileRecording = true;
616
617 return 0;
618}
619
620int TransmitMixer::StartRecordingMicrophone(OutStream* stream,
621 const CodecInst* codecInst)
622{
623 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
624 "TransmitMixer::StartRecordingMicrophone()");
625
tommi31fc21f2016-01-21 10:37:37 -0800626 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000627
628 if (_fileRecording)
629 {
630 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
631 "StartRecordingMicrophone() is already recording");
632 return 0;
633 }
634
635 FileFormats format;
636 const uint32_t notificationTime(0); // Not supported in VoE
637 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
638
639 if (codecInst != NULL && codecInst->channels != 1)
640 {
641 _engineStatisticsPtr->SetLastError(
642 VE_BAD_ARGUMENT, kTraceError,
643 "StartRecordingMicrophone() invalid compression");
644 return (-1);
645 }
646 if (codecInst == NULL)
647 {
648 format = kFileFormatPcm16kHzFile;
649 codecInst = &dummyCodec;
650 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
651 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
652 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
653 {
654 format = kFileFormatWavFile;
655 } else
656 {
657 format = kFileFormatCompressedFile;
658 }
659
660 // Destroy the old instance
kwiberg5a25d952016-08-17 07:31:12 -0700661 if (file_recorder_) {
662 file_recorder_->RegisterModuleFileCallback(NULL);
663 file_recorder_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000664 }
665
kwiberg5a25d952016-08-17 07:31:12 -0700666 file_recorder_ = FileRecorder::CreateFileRecorder(
667 _fileRecorderId, (const FileFormats)format);
668 if (!file_recorder_) {
669 _engineStatisticsPtr->SetLastError(
670 VE_INVALID_ARGUMENT, kTraceError,
671 "StartRecordingMicrophone() fileRecorder format isnot correct");
672 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000673 }
674
kwiberg4ec01d92016-08-22 08:43:54 -0700675 if (file_recorder_->StartRecordingAudioFile(stream, *codecInst,
kwiberg5a25d952016-08-17 07:31:12 -0700676 notificationTime) != 0) {
677 _engineStatisticsPtr->SetLastError(
678 VE_BAD_FILE, kTraceError,
679 "StartRecordingAudioFile() failed to start file recording");
680 file_recorder_->StopRecording();
681 file_recorder_.reset();
682 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000683 }
684
kwiberg5a25d952016-08-17 07:31:12 -0700685 file_recorder_->RegisterModuleFileCallback(this);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000686 _fileRecording = true;
687
688 return 0;
689}
690
691
692int TransmitMixer::StopRecordingMicrophone()
693{
694 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
695 "TransmitMixer::StopRecordingMicrophone()");
696
tommi31fc21f2016-01-21 10:37:37 -0800697 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000698
699 if (!_fileRecording)
700 {
701 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
702 "StopRecordingMicrophone() isnot recording");
703 return 0;
704 }
705
kwiberg5a25d952016-08-17 07:31:12 -0700706 if (file_recorder_->StopRecording() != 0) {
707 _engineStatisticsPtr->SetLastError(
708 VE_STOP_RECORDING_FAILED, kTraceError,
709 "StopRecording(), could not stop recording");
710 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000711 }
kwiberg5a25d952016-08-17 07:31:12 -0700712 file_recorder_->RegisterModuleFileCallback(NULL);
713 file_recorder_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000714 _fileRecording = false;
715
716 return 0;
717}
718
719int TransmitMixer::StartRecordingCall(const char* fileName,
720 const CodecInst* codecInst)
721{
722 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
723 "TransmitMixer::StartRecordingCall(fileName=%s)", fileName);
724
725 if (_fileCallRecording)
726 {
727 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
728 "StartRecordingCall() is already recording");
729 return 0;
730 }
731
732 FileFormats format;
733 const uint32_t notificationTime(0); // Not supported in VoE
734 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
735
736 if (codecInst != NULL && codecInst->channels != 1)
737 {
738 _engineStatisticsPtr->SetLastError(
739 VE_BAD_ARGUMENT, kTraceError,
740 "StartRecordingCall() invalid compression");
741 return (-1);
742 }
743 if (codecInst == NULL)
744 {
745 format = kFileFormatPcm16kHzFile;
746 codecInst = &dummyCodec;
747 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
748 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
749 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
750 {
751 format = kFileFormatWavFile;
752 } else
753 {
754 format = kFileFormatCompressedFile;
755 }
756
tommi31fc21f2016-01-21 10:37:37 -0800757 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000758
759 // Destroy the old instance
kwiberg5a25d952016-08-17 07:31:12 -0700760 if (file_call_recorder_) {
761 file_call_recorder_->RegisterModuleFileCallback(NULL);
762 file_call_recorder_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000763 }
764
kwiberg5a25d952016-08-17 07:31:12 -0700765 file_call_recorder_ = FileRecorder::CreateFileRecorder(
766 _fileCallRecorderId, (const FileFormats)format);
767 if (!file_call_recorder_) {
768 _engineStatisticsPtr->SetLastError(
769 VE_INVALID_ARGUMENT, kTraceError,
770 "StartRecordingCall() fileRecorder format isnot correct");
771 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000772 }
773
kwiberg5a25d952016-08-17 07:31:12 -0700774 if (file_call_recorder_->StartRecordingAudioFile(
775 fileName, (const CodecInst&)*codecInst, notificationTime) != 0) {
776 _engineStatisticsPtr->SetLastError(
777 VE_BAD_FILE, kTraceError,
778 "StartRecordingAudioFile() failed to start file recording");
779 file_call_recorder_->StopRecording();
780 file_call_recorder_.reset();
781 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000782 }
kwiberg5a25d952016-08-17 07:31:12 -0700783 file_call_recorder_->RegisterModuleFileCallback(this);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000784 _fileCallRecording = true;
785
786 return 0;
787}
788
789int TransmitMixer::StartRecordingCall(OutStream* stream,
790 const CodecInst* codecInst)
791{
792 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
793 "TransmitMixer::StartRecordingCall()");
794
795 if (_fileCallRecording)
796 {
797 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
798 "StartRecordingCall() is already recording");
799 return 0;
800 }
801
802 FileFormats format;
803 const uint32_t notificationTime(0); // Not supported in VoE
804 CodecInst dummyCodec = { 100, "L16", 16000, 320, 1, 320000 };
805
806 if (codecInst != NULL && codecInst->channels != 1)
807 {
808 _engineStatisticsPtr->SetLastError(
809 VE_BAD_ARGUMENT, kTraceError,
810 "StartRecordingCall() invalid compression");
811 return (-1);
812 }
813 if (codecInst == NULL)
814 {
815 format = kFileFormatPcm16kHzFile;
816 codecInst = &dummyCodec;
817 } else if ((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
818 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
819 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
820 {
821 format = kFileFormatWavFile;
822 } else
823 {
824 format = kFileFormatCompressedFile;
825 }
826
tommi31fc21f2016-01-21 10:37:37 -0800827 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000828
829 // Destroy the old instance
kwiberg5a25d952016-08-17 07:31:12 -0700830 if (file_call_recorder_) {
831 file_call_recorder_->RegisterModuleFileCallback(NULL);
832 file_call_recorder_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000833 }
834
kwiberg5a25d952016-08-17 07:31:12 -0700835 file_call_recorder_ = FileRecorder::CreateFileRecorder(
836 _fileCallRecorderId, (const FileFormats)format);
837 if (!file_call_recorder_) {
838 _engineStatisticsPtr->SetLastError(
839 VE_INVALID_ARGUMENT, kTraceError,
840 "StartRecordingCall() fileRecorder format isnot correct");
841 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000842 }
843
kwiberg4ec01d92016-08-22 08:43:54 -0700844 if (file_call_recorder_->StartRecordingAudioFile(stream, *codecInst,
kwiberg5a25d952016-08-17 07:31:12 -0700845 notificationTime) != 0) {
846 _engineStatisticsPtr->SetLastError(
847 VE_BAD_FILE, kTraceError,
848 "StartRecordingAudioFile() failed to start file recording");
849 file_call_recorder_->StopRecording();
850 file_call_recorder_.reset();
851 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000852 }
853
kwiberg5a25d952016-08-17 07:31:12 -0700854 file_call_recorder_->RegisterModuleFileCallback(this);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000855 _fileCallRecording = true;
856
857 return 0;
858}
859
860int TransmitMixer::StopRecordingCall()
861{
862 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
863 "TransmitMixer::StopRecordingCall()");
864
865 if (!_fileCallRecording)
866 {
867 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
868 "StopRecordingCall() file isnot recording");
869 return -1;
870 }
871
tommi31fc21f2016-01-21 10:37:37 -0800872 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000873
kwiberg5a25d952016-08-17 07:31:12 -0700874 if (file_call_recorder_->StopRecording() != 0) {
875 _engineStatisticsPtr->SetLastError(
876 VE_STOP_RECORDING_FAILED, kTraceError,
877 "StopRecording(), could not stop recording");
878 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000879 }
880
kwiberg5a25d952016-08-17 07:31:12 -0700881 file_call_recorder_->RegisterModuleFileCallback(NULL);
882 file_call_recorder_.reset();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000883 _fileCallRecording = false;
884
885 return 0;
886}
887
888void
889TransmitMixer::SetMixWithMicStatus(bool mix)
890{
891 _mixFileWithMicrophone = mix;
892}
893
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000894int8_t TransmitMixer::AudioLevel() const
895{
896 // Speech + file level [0,9]
897 return _audioLevel.Level();
898}
899
900int16_t TransmitMixer::AudioLevelFullRange() const
901{
902 // Speech + file level [0,32767]
903 return _audioLevel.LevelFullRange();
904}
905
906bool TransmitMixer::IsRecordingCall()
907{
908 return _fileCallRecording;
909}
910
911bool TransmitMixer::IsRecordingMic()
912{
tommi31fc21f2016-01-21 10:37:37 -0800913 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000914 return _fileRecording;
915}
916
917void TransmitMixer::GenerateAudioFrame(const int16_t* audio,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700918 size_t samples_per_channel,
Peter Kasting69558702016-01-12 16:26:35 -0800919 size_t num_channels,
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000920 int sample_rate_hz) {
921 int codec_rate;
Peter Kasting69558702016-01-12 16:26:35 -0800922 size_t num_codec_channels;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000923 GetSendCodecInfo(&codec_rate, &num_codec_channels);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000924 stereo_codec_ = num_codec_channels == 2;
925
Alejandro Luebscdfe20b2015-09-23 12:49:12 -0700926 // We want to process at the lowest rate possible without losing information.
927 // Choose the lowest native rate at least equal to the input and codec rates.
928 const int min_processing_rate = std::min(sample_rate_hz, codec_rate);
929 for (size_t i = 0; i < AudioProcessing::kNumNativeSampleRates; ++i) {
930 _audioFrame.sample_rate_hz_ = AudioProcessing::kNativeSampleRatesHz[i];
931 if (_audioFrame.sample_rate_hz_ >= min_processing_rate) {
932 break;
933 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000934 }
Alejandro Luebscdfe20b2015-09-23 12:49:12 -0700935 _audioFrame.num_channels_ = std::min(num_channels, num_codec_channels);
936 RemixAndResample(audio, samples_per_channel, num_channels, sample_rate_hz,
937 &resampler_, &_audioFrame);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000938}
939
940int32_t TransmitMixer::RecordAudioToFile(
941 uint32_t mixingFrequency)
942{
tommi31fc21f2016-01-21 10:37:37 -0800943 rtc::CritScope cs(&_critSect);
kwiberg5a25d952016-08-17 07:31:12 -0700944 if (!file_recorder_) {
945 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
946 "TransmitMixer::RecordAudioToFile() filerecorder doesnot"
947 "exist");
948 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000949 }
950
kwiberg5a25d952016-08-17 07:31:12 -0700951 if (file_recorder_->RecordAudioToFile(_audioFrame) != 0) {
952 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
953 "TransmitMixer::RecordAudioToFile() file recording"
954 "failed");
955 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000956 }
957
958 return 0;
959}
960
961int32_t TransmitMixer::MixOrReplaceAudioWithFile(
962 int mixingFrequency)
963{
kwibergb7f89d62016-02-17 10:04:18 -0800964 std::unique_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000965
Peter Kastingdce40cf2015-08-24 14:52:23 -0700966 size_t fileSamples(0);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000967 {
tommi31fc21f2016-01-21 10:37:37 -0800968 rtc::CritScope cs(&_critSect);
kwiberg5a25d952016-08-17 07:31:12 -0700969 if (!file_player_) {
970 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
971 "TransmitMixer::MixOrReplaceAudioWithFile()"
972 "fileplayer doesnot exist");
973 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000974 }
975
kwiberg4ec01d92016-08-22 08:43:54 -0700976 if (file_player_->Get10msAudioFromFile(fileBuffer.get(), &fileSamples,
kwiberg5a25d952016-08-17 07:31:12 -0700977 mixingFrequency) == -1) {
978 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
979 "TransmitMixer::MixOrReplaceAudioWithFile() file"
980 " mixing failed");
981 return -1;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000982 }
983 }
984
985 assert(_audioFrame.samples_per_channel_ == fileSamples);
986
987 if (_mixFileWithMicrophone)
988 {
989 // Currently file stream is always mono.
990 // TODO(xians): Change the code when FilePlayer supports real stereo.
991 MixWithSat(_audioFrame.data_,
992 _audioFrame.num_channels_,
993 fileBuffer.get(),
994 1,
995 fileSamples);
996 } else
997 {
998 // Replace ACM audio with file.
999 // Currently file stream is always mono.
1000 // TODO(xians): Change the code when FilePlayer supports real stereo.
1001 _audioFrame.UpdateFrame(-1,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00001002 0xFFFFFFFF,
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001003 fileBuffer.get(),
1004 fileSamples,
1005 mixingFrequency,
1006 AudioFrame::kNormalSpeech,
1007 AudioFrame::kVadUnknown,
1008 1);
1009 }
1010 return 0;
1011}
1012
1013void TransmitMixer::ProcessAudio(int delay_ms, int clock_drift,
1014 int current_mic_level, bool key_pressed) {
1015 if (audioproc_->set_stream_delay_ms(delay_ms) != 0) {
pbosad856222015-11-27 09:48:36 -08001016 // Silently ignore this failure to avoid flooding the logs.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001017 }
1018
1019 GainControl* agc = audioproc_->gain_control();
1020 if (agc->set_stream_analog_level(current_mic_level) != 0) {
pbosad856222015-11-27 09:48:36 -08001021 LOG(LS_ERROR) << "set_stream_analog_level failed: current_mic_level = "
1022 << current_mic_level;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001023 assert(false);
1024 }
1025
1026 EchoCancellation* aec = audioproc_->echo_cancellation();
1027 if (aec->is_drift_compensation_enabled()) {
1028 aec->set_stream_drift_samples(clock_drift);
1029 }
1030
1031 audioproc_->set_stream_key_pressed(key_pressed);
1032
1033 int err = audioproc_->ProcessStream(&_audioFrame);
1034 if (err != 0) {
1035 LOG(LS_ERROR) << "ProcessStream() error: " << err;
1036 assert(false);
1037 }
1038
1039 // Store new capture level. Only updated when analog AGC is enabled.
1040 _captureLevel = agc->stream_analog_level();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001041}
1042
henrik.lundinf00082d2016-12-05 02:22:12 -08001043#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001044void TransmitMixer::TypingDetection(bool keyPressed)
1045{
1046 // We let the VAD determine if we're using this feature or not.
1047 if (_audioFrame.vad_activity_ == AudioFrame::kVadUnknown) {
1048 return;
1049 }
1050
1051 bool vadActive = _audioFrame.vad_activity_ == AudioFrame::kVadActive;
1052 if (_typingDetection.Process(keyPressed, vadActive)) {
tommi31fc21f2016-01-21 10:37:37 -08001053 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001054 _typingNoiseWarningPending = true;
1055 _typingNoiseDetected = true;
1056 } else {
tommi31fc21f2016-01-21 10:37:37 -08001057 rtc::CritScope cs(&_critSect);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001058 // If there is already a warning pending, do not change the state.
1059 // Otherwise set a warning pending if last callback was for noise detected.
1060 if (!_typingNoiseWarningPending && _typingNoiseDetected) {
1061 _typingNoiseWarningPending = true;
1062 _typingNoiseDetected = false;
1063 }
1064 }
1065}
1066#endif
1067
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00001068void TransmitMixer::EnableStereoChannelSwapping(bool enable) {
1069 swap_stereo_channels_ = enable;
1070}
1071
1072bool TransmitMixer::IsStereoChannelSwappingEnabled() {
1073 return swap_stereo_channels_;
1074}
1075
1076} // namespace voe
1077} // namespace webrtc