blob: a90ad4892a7b9b1b9ff47d5a6dd7a89d301710d3 [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "voice_engine/transmit_mixer.h"
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000012
kwibergb7f89d62016-02-17 10:04:18 -080013#include <memory>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "audio/utility/audio_frame_operations.h"
16#include "rtc_base/format_macros.h"
17#include "rtc_base/location.h"
18#include "rtc_base/logging.h"
19#include "system_wrappers/include/event_wrapper.h"
20#include "system_wrappers/include/trace.h"
21#include "voice_engine/channel.h"
22#include "voice_engine/channel_manager.h"
23#include "voice_engine/statistics.h"
24#include "voice_engine/utility.h"
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000025
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000026namespace webrtc {
27namespace voe {
28
solenbergfc3a2e32017-09-26 09:35:01 -070029// TODO(solenberg): The thread safety in this class is dubious.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000030
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000031int32_t
32TransmitMixer::Create(TransmitMixer*& mixer, uint32_t instanceId)
33{
34 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, -1),
35 "TransmitMixer::Create(instanceId=%d)", instanceId);
36 mixer = new TransmitMixer(instanceId);
37 if (mixer == NULL)
38 {
39 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, -1),
40 "TransmitMixer::Create() unable to allocate memory"
41 "for mixer");
42 return -1;
43 }
44 return 0;
45}
46
47void
48TransmitMixer::Destroy(TransmitMixer*& mixer)
49{
50 if (mixer)
51 {
52 delete mixer;
53 mixer = NULL;
54 }
55}
56
57TransmitMixer::TransmitMixer(uint32_t instanceId) :
solenberg76377c52017-02-21 00:54:31 -080058 _instanceId(instanceId)
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000059{
60 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1),
61 "TransmitMixer::TransmitMixer() - ctor");
62}
63
solenbergfc3a2e32017-09-26 09:35:01 -070064TransmitMixer::~TransmitMixer() = default;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000065
solenbergfc3a2e32017-09-26 09:35:01 -070066void TransmitMixer::SetEngineInformation(ChannelManager* channelManager) {
67 _channelManagerPtr = channelManager;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000068}
69
70int32_t
71TransmitMixer::SetAudioProcessingModule(AudioProcessing* audioProcessingModule)
72{
73 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
74 "TransmitMixer::SetAudioProcessingModule("
75 "audioProcessingModule=0x%x)",
76 audioProcessingModule);
77 audioproc_ = audioProcessingModule;
78 return 0;
79}
80
Peter Kasting69558702016-01-12 16:26:35 -080081void TransmitMixer::GetSendCodecInfo(int* max_sample_rate,
82 size_t* max_channels) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000083 *max_sample_rate = 8000;
84 *max_channels = 1;
85 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
86 it.Increment()) {
87 Channel* channel = it.GetChannel();
88 if (channel->Sending()) {
89 CodecInst codec;
ossu950c1c92017-07-11 08:19:31 -070090 // TODO(ossu): Investigate how this could happen. b/62909493
91 if (channel->GetSendCodec(codec) == 0) {
92 *max_sample_rate = std::max(*max_sample_rate, codec.plfreq);
93 *max_channels = std::max(*max_channels, codec.channels);
94 } else {
95 LOG(LS_WARNING) << "Unable to get send codec for channel "
96 << channel->ChannelId();
97 RTC_NOTREACHED();
98 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000099 }
100 }
101}
102
103int32_t
104TransmitMixer::PrepareDemux(const void* audioSamples,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700105 size_t nSamples,
Peter Kasting69558702016-01-12 16:26:35 -0800106 size_t nChannels,
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000107 uint32_t samplesPerSec,
108 uint16_t totalDelayMS,
109 int32_t clockDrift,
110 uint16_t currentMicLevel,
111 bool keyPressed)
112{
113 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
Peter Kastingdce40cf2015-08-24 14:52:23 -0700114 "TransmitMixer::PrepareDemux(nSamples=%" PRIuS ", "
Peter Kasting69558702016-01-12 16:26:35 -0800115 "nChannels=%" PRIuS ", samplesPerSec=%u, totalDelayMS=%u, "
Peter Kastingdce40cf2015-08-24 14:52:23 -0700116 "clockDrift=%d, currentMicLevel=%u)",
117 nSamples, nChannels, samplesPerSec, totalDelayMS, clockDrift,
118 currentMicLevel);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000119
120 // --- Resample input audio and create/store the initial audio frame
121 GenerateAudioFrame(static_cast<const int16_t*>(audioSamples),
122 nSamples,
123 nChannels,
124 samplesPerSec);
125
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000126 // --- Near-end audio processing.
127 ProcessAudio(totalDelayMS, clockDrift, currentMicLevel, keyPressed);
128
129 if (swap_stereo_channels_ && stereo_codec_)
130 // Only bother swapping if we're using a stereo codec.
131 AudioFrameOperations::SwapStereoChannels(&_audioFrame);
132
133 // --- Annoying typing detection (utilizes the APM/VAD decision)
henrik.lundinf00082d2016-12-05 02:22:12 -0800134#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000135 TypingDetection(keyPressed);
136#endif
137
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000138 // --- Measure audio level of speech after all processing.
zsteine76bd3a2017-07-14 12:17:49 -0700139 double sample_duration = static_cast<double>(nSamples) / samplesPerSec;
zstein3c451862017-07-20 09:57:42 -0700140 _audioLevel.ComputeLevel(_audioFrame, sample_duration);
zsteine76bd3a2017-07-14 12:17:49 -0700141
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000142 return 0;
143}
144
henrikaec6fbd22017-03-31 05:43:36 -0700145void TransmitMixer::ProcessAndEncodeAudio() {
146 RTC_DCHECK_GT(_audioFrame.samples_per_channel_, 0);
147 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
148 it.Increment()) {
149 Channel* const channel = it.GetChannel();
150 if (channel->Sending()) {
151 channel->ProcessAndEncodeAudio(_audioFrame);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000152 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000153 }
154}
155
156uint32_t TransmitMixer::CaptureLevel() const
157{
158 return _captureLevel;
159}
160
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000161int32_t
162TransmitMixer::StopSend()
163{
164 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
165 "TransmitMixer::StopSend()");
166 _audioLevel.Clear();
167 return 0;
168}
169
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000170int8_t TransmitMixer::AudioLevel() const
171{
172 // Speech + file level [0,9]
173 return _audioLevel.Level();
174}
175
176int16_t TransmitMixer::AudioLevelFullRange() const
177{
178 // Speech + file level [0,32767]
179 return _audioLevel.LevelFullRange();
180}
181
zsteine76bd3a2017-07-14 12:17:49 -0700182double TransmitMixer::GetTotalInputEnergy() const {
zstein3c451862017-07-20 09:57:42 -0700183 return _audioLevel.TotalEnergy();
zsteine76bd3a2017-07-14 12:17:49 -0700184}
185
186double TransmitMixer::GetTotalInputDuration() const {
zstein3c451862017-07-20 09:57:42 -0700187 return _audioLevel.TotalDuration();
zsteine76bd3a2017-07-14 12:17:49 -0700188}
189
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000190void TransmitMixer::GenerateAudioFrame(const int16_t* audio,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700191 size_t samples_per_channel,
Peter Kasting69558702016-01-12 16:26:35 -0800192 size_t num_channels,
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000193 int sample_rate_hz) {
194 int codec_rate;
Peter Kasting69558702016-01-12 16:26:35 -0800195 size_t num_codec_channels;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000196 GetSendCodecInfo(&codec_rate, &num_codec_channels);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000197 stereo_codec_ = num_codec_channels == 2;
198
Alejandro Luebscdfe20b2015-09-23 12:49:12 -0700199 // We want to process at the lowest rate possible without losing information.
200 // Choose the lowest native rate at least equal to the input and codec rates.
201 const int min_processing_rate = std::min(sample_rate_hz, codec_rate);
202 for (size_t i = 0; i < AudioProcessing::kNumNativeSampleRates; ++i) {
203 _audioFrame.sample_rate_hz_ = AudioProcessing::kNativeSampleRatesHz[i];
204 if (_audioFrame.sample_rate_hz_ >= min_processing_rate) {
205 break;
206 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000207 }
Alejandro Luebscdfe20b2015-09-23 12:49:12 -0700208 _audioFrame.num_channels_ = std::min(num_channels, num_codec_channels);
209 RemixAndResample(audio, samples_per_channel, num_channels, sample_rate_hz,
210 &resampler_, &_audioFrame);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000211}
212
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000213void TransmitMixer::ProcessAudio(int delay_ms, int clock_drift,
214 int current_mic_level, bool key_pressed) {
215 if (audioproc_->set_stream_delay_ms(delay_ms) != 0) {
pbosad856222015-11-27 09:48:36 -0800216 // Silently ignore this failure to avoid flooding the logs.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000217 }
218
219 GainControl* agc = audioproc_->gain_control();
220 if (agc->set_stream_analog_level(current_mic_level) != 0) {
pbosad856222015-11-27 09:48:36 -0800221 LOG(LS_ERROR) << "set_stream_analog_level failed: current_mic_level = "
222 << current_mic_level;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000223 assert(false);
224 }
225
226 EchoCancellation* aec = audioproc_->echo_cancellation();
227 if (aec->is_drift_compensation_enabled()) {
228 aec->set_stream_drift_samples(clock_drift);
229 }
230
231 audioproc_->set_stream_key_pressed(key_pressed);
232
233 int err = audioproc_->ProcessStream(&_audioFrame);
234 if (err != 0) {
235 LOG(LS_ERROR) << "ProcessStream() error: " << err;
236 assert(false);
237 }
238
239 // Store new capture level. Only updated when analog AGC is enabled.
240 _captureLevel = agc->stream_analog_level();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000241}
242
henrik.lundinf00082d2016-12-05 02:22:12 -0800243#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
solenbergfc3a2e32017-09-26 09:35:01 -0700244void TransmitMixer::TypingDetection(bool key_pressed)
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000245{
246 // We let the VAD determine if we're using this feature or not.
247 if (_audioFrame.vad_activity_ == AudioFrame::kVadUnknown) {
248 return;
249 }
250
solenbergfc3a2e32017-09-26 09:35:01 -0700251 bool vad_active = _audioFrame.vad_activity_ == AudioFrame::kVadActive;
252 bool typing_detected = typing_detection_.Process(key_pressed, vad_active);
253
254 rtc::CritScope cs(&lock_);
255 typing_noise_detected_ = typing_detected;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000256}
257#endif
258
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000259void TransmitMixer::EnableStereoChannelSwapping(bool enable) {
260 swap_stereo_channels_ = enable;
261}
262
263bool TransmitMixer::IsStereoChannelSwappingEnabled() {
264 return swap_stereo_channels_;
265}
266
solenbergfc3a2e32017-09-26 09:35:01 -0700267bool TransmitMixer::typing_noise_detected() const {
268 rtc::CritScope cs(&lock_);
269 return typing_noise_detected_;
270}
271
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000272} // namespace voe
273} // namespace webrtc