blob: 8fe1d2584a36c8657483d09765601dce7d7bfd72 [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"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "voice_engine/utility.h"
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000024
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000025namespace webrtc {
26namespace voe {
27
solenbergfc3a2e32017-09-26 09:35:01 -070028// TODO(solenberg): The thread safety in this class is dubious.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000029
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000030int32_t
31TransmitMixer::Create(TransmitMixer*& mixer, uint32_t instanceId)
32{
33 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, -1),
34 "TransmitMixer::Create(instanceId=%d)", instanceId);
35 mixer = new TransmitMixer(instanceId);
36 if (mixer == NULL)
37 {
38 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, -1),
39 "TransmitMixer::Create() unable to allocate memory"
40 "for mixer");
41 return -1;
42 }
43 return 0;
44}
45
46void
47TransmitMixer::Destroy(TransmitMixer*& mixer)
48{
49 if (mixer)
50 {
51 delete mixer;
52 mixer = NULL;
53 }
54}
55
56TransmitMixer::TransmitMixer(uint32_t instanceId) :
solenberg76377c52017-02-21 00:54:31 -080057 _instanceId(instanceId)
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000058{
59 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1),
60 "TransmitMixer::TransmitMixer() - ctor");
61}
62
solenbergfc3a2e32017-09-26 09:35:01 -070063TransmitMixer::~TransmitMixer() = default;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000064
solenbergfc3a2e32017-09-26 09:35:01 -070065void TransmitMixer::SetEngineInformation(ChannelManager* channelManager) {
66 _channelManagerPtr = channelManager;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000067}
68
69int32_t
70TransmitMixer::SetAudioProcessingModule(AudioProcessing* audioProcessingModule)
71{
72 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
73 "TransmitMixer::SetAudioProcessingModule("
74 "audioProcessingModule=0x%x)",
75 audioProcessingModule);
76 audioproc_ = audioProcessingModule;
77 return 0;
78}
79
Peter Kasting69558702016-01-12 16:26:35 -080080void TransmitMixer::GetSendCodecInfo(int* max_sample_rate,
81 size_t* max_channels) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000082 *max_sample_rate = 8000;
83 *max_channels = 1;
84 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
85 it.Increment()) {
86 Channel* channel = it.GetChannel();
87 if (channel->Sending()) {
88 CodecInst codec;
ossu950c1c92017-07-11 08:19:31 -070089 // TODO(ossu): Investigate how this could happen. b/62909493
90 if (channel->GetSendCodec(codec) == 0) {
91 *max_sample_rate = std::max(*max_sample_rate, codec.plfreq);
92 *max_channels = std::max(*max_channels, codec.channels);
93 } else {
94 LOG(LS_WARNING) << "Unable to get send codec for channel "
95 << channel->ChannelId();
96 RTC_NOTREACHED();
97 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000098 }
99 }
100}
101
102int32_t
103TransmitMixer::PrepareDemux(const void* audioSamples,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700104 size_t nSamples,
Peter Kasting69558702016-01-12 16:26:35 -0800105 size_t nChannels,
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000106 uint32_t samplesPerSec,
107 uint16_t totalDelayMS,
108 int32_t clockDrift,
109 uint16_t currentMicLevel,
110 bool keyPressed)
111{
112 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
Peter Kastingdce40cf2015-08-24 14:52:23 -0700113 "TransmitMixer::PrepareDemux(nSamples=%" PRIuS ", "
Peter Kasting69558702016-01-12 16:26:35 -0800114 "nChannels=%" PRIuS ", samplesPerSec=%u, totalDelayMS=%u, "
Peter Kastingdce40cf2015-08-24 14:52:23 -0700115 "clockDrift=%d, currentMicLevel=%u)",
116 nSamples, nChannels, samplesPerSec, totalDelayMS, clockDrift,
117 currentMicLevel);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000118
119 // --- Resample input audio and create/store the initial audio frame
120 GenerateAudioFrame(static_cast<const int16_t*>(audioSamples),
121 nSamples,
122 nChannels,
123 samplesPerSec);
124
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000125 // --- Near-end audio processing.
126 ProcessAudio(totalDelayMS, clockDrift, currentMicLevel, keyPressed);
127
128 if (swap_stereo_channels_ && stereo_codec_)
129 // Only bother swapping if we're using a stereo codec.
130 AudioFrameOperations::SwapStereoChannels(&_audioFrame);
131
132 // --- Annoying typing detection (utilizes the APM/VAD decision)
henrik.lundinf00082d2016-12-05 02:22:12 -0800133#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000134 TypingDetection(keyPressed);
135#endif
136
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000137 // --- Measure audio level of speech after all processing.
zsteine76bd3a2017-07-14 12:17:49 -0700138 double sample_duration = static_cast<double>(nSamples) / samplesPerSec;
zstein3c451862017-07-20 09:57:42 -0700139 _audioLevel.ComputeLevel(_audioFrame, sample_duration);
zsteine76bd3a2017-07-14 12:17:49 -0700140
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000141 return 0;
142}
143
henrikaec6fbd22017-03-31 05:43:36 -0700144void TransmitMixer::ProcessAndEncodeAudio() {
145 RTC_DCHECK_GT(_audioFrame.samples_per_channel_, 0);
146 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
147 it.Increment()) {
148 Channel* const channel = it.GetChannel();
149 if (channel->Sending()) {
150 channel->ProcessAndEncodeAudio(_audioFrame);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000151 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000152 }
153}
154
155uint32_t TransmitMixer::CaptureLevel() const
156{
157 return _captureLevel;
158}
159
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000160int32_t
161TransmitMixer::StopSend()
162{
163 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
164 "TransmitMixer::StopSend()");
165 _audioLevel.Clear();
166 return 0;
167}
168
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000169int8_t TransmitMixer::AudioLevel() const
170{
171 // Speech + file level [0,9]
172 return _audioLevel.Level();
173}
174
175int16_t TransmitMixer::AudioLevelFullRange() const
176{
177 // Speech + file level [0,32767]
178 return _audioLevel.LevelFullRange();
179}
180
zsteine76bd3a2017-07-14 12:17:49 -0700181double TransmitMixer::GetTotalInputEnergy() const {
zstein3c451862017-07-20 09:57:42 -0700182 return _audioLevel.TotalEnergy();
zsteine76bd3a2017-07-14 12:17:49 -0700183}
184
185double TransmitMixer::GetTotalInputDuration() const {
zstein3c451862017-07-20 09:57:42 -0700186 return _audioLevel.TotalDuration();
zsteine76bd3a2017-07-14 12:17:49 -0700187}
188
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000189void TransmitMixer::GenerateAudioFrame(const int16_t* audio,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700190 size_t samples_per_channel,
Peter Kasting69558702016-01-12 16:26:35 -0800191 size_t num_channels,
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000192 int sample_rate_hz) {
193 int codec_rate;
Peter Kasting69558702016-01-12 16:26:35 -0800194 size_t num_codec_channels;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000195 GetSendCodecInfo(&codec_rate, &num_codec_channels);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000196 stereo_codec_ = num_codec_channels == 2;
197
Alejandro Luebscdfe20b2015-09-23 12:49:12 -0700198 // We want to process at the lowest rate possible without losing information.
199 // Choose the lowest native rate at least equal to the input and codec rates.
200 const int min_processing_rate = std::min(sample_rate_hz, codec_rate);
201 for (size_t i = 0; i < AudioProcessing::kNumNativeSampleRates; ++i) {
202 _audioFrame.sample_rate_hz_ = AudioProcessing::kNativeSampleRatesHz[i];
203 if (_audioFrame.sample_rate_hz_ >= min_processing_rate) {
204 break;
205 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000206 }
Alejandro Luebscdfe20b2015-09-23 12:49:12 -0700207 _audioFrame.num_channels_ = std::min(num_channels, num_codec_channels);
208 RemixAndResample(audio, samples_per_channel, num_channels, sample_rate_hz,
209 &resampler_, &_audioFrame);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000210}
211
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000212void TransmitMixer::ProcessAudio(int delay_ms, int clock_drift,
213 int current_mic_level, bool key_pressed) {
214 if (audioproc_->set_stream_delay_ms(delay_ms) != 0) {
pbosad856222015-11-27 09:48:36 -0800215 // Silently ignore this failure to avoid flooding the logs.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000216 }
217
218 GainControl* agc = audioproc_->gain_control();
219 if (agc->set_stream_analog_level(current_mic_level) != 0) {
pbosad856222015-11-27 09:48:36 -0800220 LOG(LS_ERROR) << "set_stream_analog_level failed: current_mic_level = "
221 << current_mic_level;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000222 assert(false);
223 }
224
225 EchoCancellation* aec = audioproc_->echo_cancellation();
226 if (aec->is_drift_compensation_enabled()) {
227 aec->set_stream_drift_samples(clock_drift);
228 }
229
230 audioproc_->set_stream_key_pressed(key_pressed);
231
232 int err = audioproc_->ProcessStream(&_audioFrame);
233 if (err != 0) {
234 LOG(LS_ERROR) << "ProcessStream() error: " << err;
235 assert(false);
236 }
237
238 // Store new capture level. Only updated when analog AGC is enabled.
239 _captureLevel = agc->stream_analog_level();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000240}
241
henrik.lundinf00082d2016-12-05 02:22:12 -0800242#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
solenbergfc3a2e32017-09-26 09:35:01 -0700243void TransmitMixer::TypingDetection(bool key_pressed)
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000244{
245 // We let the VAD determine if we're using this feature or not.
246 if (_audioFrame.vad_activity_ == AudioFrame::kVadUnknown) {
247 return;
248 }
249
solenbergfc3a2e32017-09-26 09:35:01 -0700250 bool vad_active = _audioFrame.vad_activity_ == AudioFrame::kVadActive;
251 bool typing_detected = typing_detection_.Process(key_pressed, vad_active);
252
253 rtc::CritScope cs(&lock_);
254 typing_noise_detected_ = typing_detected;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000255}
256#endif
257
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000258void TransmitMixer::EnableStereoChannelSwapping(bool enable) {
259 swap_stereo_channels_ = enable;
260}
261
262bool TransmitMixer::IsStereoChannelSwappingEnabled() {
263 return swap_stereo_channels_;
264}
265
solenbergfc3a2e32017-09-26 09:35:01 -0700266bool TransmitMixer::typing_noise_detected() const {
267 rtc::CritScope cs(&lock_);
268 return typing_noise_detected_;
269}
270
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000271} // namespace voe
272} // namespace webrtc