blob: c8e8200206a079907453e1f100121321ea904386 [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"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "voice_engine/channel.h"
21#include "voice_engine/channel_manager.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "voice_engine/utility.h"
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000023
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000024namespace webrtc {
25namespace voe {
26
solenbergfc3a2e32017-09-26 09:35:01 -070027// TODO(solenberg): The thread safety in this class is dubious.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000028
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000029int32_t
Fredrik Solenberg4332d092017-10-04 09:53:35 +020030TransmitMixer::Create(TransmitMixer*& mixer)
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000031{
Fredrik Solenberg4332d092017-10-04 09:53:35 +020032 mixer = new TransmitMixer();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000033 if (mixer == NULL)
34 {
Fredrik Solenberg4332d092017-10-04 09:53:35 +020035 LOG(LS_ERROR) << "TransmitMixer::Create() unable to allocate memory "
36 "for mixer";
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000037 return -1;
38 }
39 return 0;
40}
41
42void
43TransmitMixer::Destroy(TransmitMixer*& mixer)
44{
45 if (mixer)
46 {
47 delete mixer;
48 mixer = NULL;
49 }
50}
51
solenbergfc3a2e32017-09-26 09:35:01 -070052TransmitMixer::~TransmitMixer() = default;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000053
solenbergfc3a2e32017-09-26 09:35:01 -070054void TransmitMixer::SetEngineInformation(ChannelManager* channelManager) {
55 _channelManagerPtr = channelManager;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000056}
57
58int32_t
59TransmitMixer::SetAudioProcessingModule(AudioProcessing* audioProcessingModule)
60{
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000061 audioproc_ = audioProcessingModule;
62 return 0;
63}
64
Peter Kasting69558702016-01-12 16:26:35 -080065void TransmitMixer::GetSendCodecInfo(int* max_sample_rate,
66 size_t* max_channels) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000067 *max_sample_rate = 8000;
68 *max_channels = 1;
69 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
70 it.Increment()) {
71 Channel* channel = it.GetChannel();
72 if (channel->Sending()) {
73 CodecInst codec;
ossu950c1c92017-07-11 08:19:31 -070074 // TODO(ossu): Investigate how this could happen. b/62909493
75 if (channel->GetSendCodec(codec) == 0) {
76 *max_sample_rate = std::max(*max_sample_rate, codec.plfreq);
77 *max_channels = std::max(*max_channels, codec.channels);
78 } else {
79 LOG(LS_WARNING) << "Unable to get send codec for channel "
80 << channel->ChannelId();
81 RTC_NOTREACHED();
82 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000083 }
84 }
85}
86
87int32_t
88TransmitMixer::PrepareDemux(const void* audioSamples,
Peter Kastingdce40cf2015-08-24 14:52:23 -070089 size_t nSamples,
Peter Kasting69558702016-01-12 16:26:35 -080090 size_t nChannels,
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000091 uint32_t samplesPerSec,
92 uint16_t totalDelayMS,
93 int32_t clockDrift,
94 uint16_t currentMicLevel,
95 bool keyPressed)
96{
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +000097 // --- Resample input audio and create/store the initial audio frame
98 GenerateAudioFrame(static_cast<const int16_t*>(audioSamples),
99 nSamples,
100 nChannels,
101 samplesPerSec);
102
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000103 // --- Near-end audio processing.
104 ProcessAudio(totalDelayMS, clockDrift, currentMicLevel, keyPressed);
105
106 if (swap_stereo_channels_ && stereo_codec_)
107 // Only bother swapping if we're using a stereo codec.
108 AudioFrameOperations::SwapStereoChannels(&_audioFrame);
109
110 // --- Annoying typing detection (utilizes the APM/VAD decision)
henrik.lundinf00082d2016-12-05 02:22:12 -0800111#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000112 TypingDetection(keyPressed);
113#endif
114
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000115 // --- Measure audio level of speech after all processing.
zsteine76bd3a2017-07-14 12:17:49 -0700116 double sample_duration = static_cast<double>(nSamples) / samplesPerSec;
zstein3c451862017-07-20 09:57:42 -0700117 _audioLevel.ComputeLevel(_audioFrame, sample_duration);
zsteine76bd3a2017-07-14 12:17:49 -0700118
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000119 return 0;
120}
121
henrikaec6fbd22017-03-31 05:43:36 -0700122void TransmitMixer::ProcessAndEncodeAudio() {
123 RTC_DCHECK_GT(_audioFrame.samples_per_channel_, 0);
124 for (ChannelManager::Iterator it(_channelManagerPtr); it.IsValid();
125 it.Increment()) {
126 Channel* const channel = it.GetChannel();
127 if (channel->Sending()) {
128 channel->ProcessAndEncodeAudio(_audioFrame);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000129 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000130 }
131}
132
133uint32_t TransmitMixer::CaptureLevel() const
134{
135 return _captureLevel;
136}
137
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000138int32_t
139TransmitMixer::StopSend()
140{
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000141 _audioLevel.Clear();
142 return 0;
143}
144
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000145int8_t TransmitMixer::AudioLevel() const
146{
147 // Speech + file level [0,9]
148 return _audioLevel.Level();
149}
150
151int16_t TransmitMixer::AudioLevelFullRange() const
152{
153 // Speech + file level [0,32767]
154 return _audioLevel.LevelFullRange();
155}
156
zsteine76bd3a2017-07-14 12:17:49 -0700157double TransmitMixer::GetTotalInputEnergy() const {
zstein3c451862017-07-20 09:57:42 -0700158 return _audioLevel.TotalEnergy();
zsteine76bd3a2017-07-14 12:17:49 -0700159}
160
161double TransmitMixer::GetTotalInputDuration() const {
zstein3c451862017-07-20 09:57:42 -0700162 return _audioLevel.TotalDuration();
zsteine76bd3a2017-07-14 12:17:49 -0700163}
164
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000165void TransmitMixer::GenerateAudioFrame(const int16_t* audio,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700166 size_t samples_per_channel,
Peter Kasting69558702016-01-12 16:26:35 -0800167 size_t num_channels,
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000168 int sample_rate_hz) {
169 int codec_rate;
Peter Kasting69558702016-01-12 16:26:35 -0800170 size_t num_codec_channels;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000171 GetSendCodecInfo(&codec_rate, &num_codec_channels);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000172 stereo_codec_ = num_codec_channels == 2;
173
Alejandro Luebscdfe20b2015-09-23 12:49:12 -0700174 // We want to process at the lowest rate possible without losing information.
175 // Choose the lowest native rate at least equal to the input and codec rates.
176 const int min_processing_rate = std::min(sample_rate_hz, codec_rate);
177 for (size_t i = 0; i < AudioProcessing::kNumNativeSampleRates; ++i) {
178 _audioFrame.sample_rate_hz_ = AudioProcessing::kNativeSampleRatesHz[i];
179 if (_audioFrame.sample_rate_hz_ >= min_processing_rate) {
180 break;
181 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000182 }
Alejandro Luebscdfe20b2015-09-23 12:49:12 -0700183 _audioFrame.num_channels_ = std::min(num_channels, num_codec_channels);
184 RemixAndResample(audio, samples_per_channel, num_channels, sample_rate_hz,
185 &resampler_, &_audioFrame);
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000186}
187
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000188void TransmitMixer::ProcessAudio(int delay_ms, int clock_drift,
189 int current_mic_level, bool key_pressed) {
190 if (audioproc_->set_stream_delay_ms(delay_ms) != 0) {
pbosad856222015-11-27 09:48:36 -0800191 // Silently ignore this failure to avoid flooding the logs.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000192 }
193
194 GainControl* agc = audioproc_->gain_control();
195 if (agc->set_stream_analog_level(current_mic_level) != 0) {
pbosad856222015-11-27 09:48:36 -0800196 LOG(LS_ERROR) << "set_stream_analog_level failed: current_mic_level = "
197 << current_mic_level;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000198 assert(false);
199 }
200
201 EchoCancellation* aec = audioproc_->echo_cancellation();
202 if (aec->is_drift_compensation_enabled()) {
203 aec->set_stream_drift_samples(clock_drift);
204 }
205
206 audioproc_->set_stream_key_pressed(key_pressed);
207
208 int err = audioproc_->ProcessStream(&_audioFrame);
209 if (err != 0) {
210 LOG(LS_ERROR) << "ProcessStream() error: " << err;
211 assert(false);
212 }
213
214 // Store new capture level. Only updated when analog AGC is enabled.
215 _captureLevel = agc->stream_analog_level();
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000216}
217
henrik.lundinf00082d2016-12-05 02:22:12 -0800218#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
solenbergfc3a2e32017-09-26 09:35:01 -0700219void TransmitMixer::TypingDetection(bool key_pressed)
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000220{
221 // We let the VAD determine if we're using this feature or not.
222 if (_audioFrame.vad_activity_ == AudioFrame::kVadUnknown) {
223 return;
224 }
225
solenbergfc3a2e32017-09-26 09:35:01 -0700226 bool vad_active = _audioFrame.vad_activity_ == AudioFrame::kVadActive;
227 bool typing_detected = typing_detection_.Process(key_pressed, vad_active);
228
229 rtc::CritScope cs(&lock_);
230 typing_noise_detected_ = typing_detected;
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000231}
232#endif
233
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000234void TransmitMixer::EnableStereoChannelSwapping(bool enable) {
235 swap_stereo_channels_ = enable;
236}
237
238bool TransmitMixer::IsStereoChannelSwappingEnabled() {
239 return swap_stereo_channels_;
240}
241
solenbergfc3a2e32017-09-26 09:35:01 -0700242bool TransmitMixer::typing_noise_detected() const {
243 rtc::CritScope cs(&lock_);
244 return typing_noise_detected_;
245}
246
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000247} // namespace voe
248} // namespace webrtc