blob: 94cd98f797feea696a2cd005654c259c970ad654 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
xians@webrtc.org79af7342012-01-31 12:22:14 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
pbos@webrtc.org956aa7e2013-05-21 13:52:32 +000011#include "webrtc/voice_engine/voe_base_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
Peter Kastingdce40cf2015-08-24 14:52:23 -070013#include "webrtc/base/format_macros.h"
turaj@webrtc.org03f33702013-11-13 00:02:48 +000014#include "webrtc/common.h"
pbos@webrtc.org956aa7e2013-05-21 13:52:32 +000015#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
16#include "webrtc/modules/audio_coding/main/interface/audio_coding_module.h"
17#include "webrtc/modules/audio_device/audio_device_impl.h"
18#include "webrtc/modules/audio_processing/include/audio_processing.h"
19#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
20#include "webrtc/system_wrappers/interface/file_wrapper.h"
Jelena Marusic9e5e4212015-04-13 13:41:56 +020021#include "webrtc/system_wrappers/interface/logging.h"
pbos@webrtc.org956aa7e2013-05-21 13:52:32 +000022#include "webrtc/voice_engine/channel.h"
23#include "webrtc/voice_engine/include/voe_errors.h"
24#include "webrtc/voice_engine/output_mixer.h"
25#include "webrtc/voice_engine/transmit_mixer.h"
26#include "webrtc/voice_engine/utility.h"
27#include "webrtc/voice_engine/voice_engine_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000028
Jelena Marusic2dd6a272015-04-14 09:47:00 +020029namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000030
Jelena Marusic2dd6a272015-04-14 09:47:00 +020031VoEBase* VoEBase::GetInterface(VoiceEngine* voiceEngine) {
32 if (nullptr == voiceEngine) {
33 return nullptr;
34 }
35 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
36 s->AddRef();
37 return s;
niklase@google.com470e71d2011-07-07 08:21:25 +000038}
39
Jelena Marusic2dd6a272015-04-14 09:47:00 +020040VoEBaseImpl::VoEBaseImpl(voe::SharedData* shared)
41 : voiceEngineObserverPtr_(nullptr),
42 callbackCritSect_(*CriticalSectionWrapper::CreateCriticalSection()),
43 shared_(shared) {}
44
45VoEBaseImpl::~VoEBaseImpl() {
46 TerminateInternal();
47 delete &callbackCritSect_;
niklase@google.com470e71d2011-07-07 08:21:25 +000048}
49
Jelena Marusic2dd6a272015-04-14 09:47:00 +020050void VoEBaseImpl::OnErrorIsReported(ErrorCode error) {
51 CriticalSectionScoped cs(&callbackCritSect_);
52 int errCode = 0;
53 if (error == AudioDeviceObserver::kRecordingError) {
54 errCode = VE_RUNTIME_REC_ERROR;
55 LOG_F(LS_ERROR) << "VE_RUNTIME_REC_ERROR";
56 } else if (error == AudioDeviceObserver::kPlayoutError) {
57 errCode = VE_RUNTIME_PLAY_ERROR;
58 LOG_F(LS_ERROR) << "VE_RUNTIME_PLAY_ERROR";
59 }
60 if (voiceEngineObserverPtr_) {
61 // Deliver callback (-1 <=> no channel dependency)
62 voiceEngineObserverPtr_->CallbackOnError(-1, errCode);
63 }
niklase@google.com470e71d2011-07-07 08:21:25 +000064}
65
Jelena Marusic2dd6a272015-04-14 09:47:00 +020066void VoEBaseImpl::OnWarningIsReported(WarningCode warning) {
67 CriticalSectionScoped cs(&callbackCritSect_);
68 int warningCode = 0;
69 if (warning == AudioDeviceObserver::kRecordingWarning) {
70 warningCode = VE_RUNTIME_REC_WARNING;
71 LOG_F(LS_WARNING) << "VE_RUNTIME_REC_WARNING";
72 } else if (warning == AudioDeviceObserver::kPlayoutWarning) {
73 warningCode = VE_RUNTIME_PLAY_WARNING;
74 LOG_F(LS_WARNING) << "VE_RUNTIME_PLAY_WARNING";
75 }
76 if (voiceEngineObserverPtr_) {
77 // Deliver callback (-1 <=> no channel dependency)
78 voiceEngineObserverPtr_->CallbackOnError(-1, warningCode);
79 }
niklase@google.com470e71d2011-07-07 08:21:25 +000080}
81
pbos@webrtc.org6141e132013-04-09 10:09:10 +000082int32_t VoEBaseImpl::RecordedDataIsAvailable(
Peter Kastingdce40cf2015-08-24 14:52:23 -070083 const void* audioSamples, size_t nSamples, size_t nBytesPerSample,
Jelena Marusic2dd6a272015-04-14 09:47:00 +020084 uint8_t nChannels, uint32_t samplesPerSec, uint32_t totalDelayMS,
85 int32_t clockDrift, uint32_t micLevel, bool keyPressed,
86 uint32_t& newMicLevel) {
87 newMicLevel = static_cast<uint32_t>(ProcessRecordedDataWithAPM(
88 nullptr, 0, audioSamples, samplesPerSec, nChannels, nSamples,
89 totalDelayMS, clockDrift, micLevel, keyPressed));
90 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000091}
92
Peter Kastingdce40cf2015-08-24 14:52:23 -070093int32_t VoEBaseImpl::NeedMorePlayData(size_t nSamples,
94 size_t nBytesPerSample,
Jelena Marusic2dd6a272015-04-14 09:47:00 +020095 uint8_t nChannels, uint32_t samplesPerSec,
Peter Kastingdce40cf2015-08-24 14:52:23 -070096 void* audioSamples, size_t& nSamplesOut,
Jelena Marusic2dd6a272015-04-14 09:47:00 +020097 int64_t* elapsed_time_ms,
98 int64_t* ntp_time_ms) {
99 GetPlayoutData(static_cast<int>(samplesPerSec), static_cast<int>(nChannels),
Peter Kastingdce40cf2015-08-24 14:52:23 -0700100 nSamples, true, audioSamples,
wu@webrtc.org94454b72014-06-05 20:34:08 +0000101 elapsed_time_ms, ntp_time_ms);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200102 nSamplesOut = audioFrame_.samples_per_channel_;
xians@webrtc.org56925312014-04-14 10:50:37 +0000103 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000104}
105
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000106int VoEBaseImpl::OnDataAvailable(const int voe_channels[],
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000107 int number_of_voe_channels,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200108 const int16_t* audio_data, int sample_rate,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700109 int number_of_channels,
110 size_t number_of_frames,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200111 int audio_delay_milliseconds, int volume,
112 bool key_pressed, bool need_audio_processing) {
113 if (number_of_voe_channels == 0) return 0;
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000114
115 if (need_audio_processing) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000116 return ProcessRecordedDataWithAPM(
117 voe_channels, number_of_voe_channels, audio_data, sample_rate,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200118 number_of_channels, number_of_frames, audio_delay_milliseconds, 0,
119 volume, key_pressed);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000120 }
121
122 // No need to go through the APM, demultiplex the data to each VoE channel,
123 // encode and send to the network.
124 for (int i = 0; i < number_of_voe_channels; ++i) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000125 // TODO(ajm): In the case where multiple channels are using the same codec
126 // rate, this path needlessly does extra conversions. We should convert once
127 // and share between channels.
xians@webrtc.org56925312014-04-14 10:50:37 +0000128 PushCaptureData(voe_channels[i], audio_data, 16, sample_rate,
129 number_of_channels, number_of_frames);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000130 }
131
132 // Return 0 to indicate no need to change the volume.
133 return 0;
134}
135
xians@webrtc.orgc1e28032014-02-02 15:30:20 +0000136void VoEBaseImpl::OnData(int voe_channel, const void* audio_data,
137 int bits_per_sample, int sample_rate,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700138 int number_of_channels, size_t number_of_frames) {
xians@webrtc.org56925312014-04-14 10:50:37 +0000139 PushCaptureData(voe_channel, audio_data, bits_per_sample, sample_rate,
140 number_of_channels, number_of_frames);
141}
142
143void VoEBaseImpl::PushCaptureData(int voe_channel, const void* audio_data,
144 int bits_per_sample, int sample_rate,
145 int number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700146 size_t number_of_frames) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200147 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(voe_channel);
xians@webrtc.org07e51962014-01-29 13:54:02 +0000148 voe::Channel* channel_ptr = ch.channel();
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200149 if (!channel_ptr) return;
xians@webrtc.org07e51962014-01-29 13:54:02 +0000150
henrika@webrtc.org66803482014-04-17 10:45:01 +0000151 if (channel_ptr->Sending()) {
xians@webrtc.org07e51962014-01-29 13:54:02 +0000152 channel_ptr->Demultiplex(static_cast<const int16_t*>(audio_data),
153 sample_rate, number_of_frames, number_of_channels);
154 channel_ptr->PrepareEncodeAndSend(sample_rate);
155 channel_ptr->EncodeAndSend();
156 }
157}
158
Peter Kastingdce40cf2015-08-24 14:52:23 -0700159void VoEBaseImpl::PullRenderData(int bits_per_sample,
160 int sample_rate,
161 int number_of_channels,
162 size_t number_of_frames,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200163 void* audio_data, int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000164 int64_t* ntp_time_ms) {
Jelena Marusic6fc2d2f2015-04-13 14:07:04 +0200165 assert(bits_per_sample == 16);
Peter Kastingdce40cf2015-08-24 14:52:23 -0700166 assert(number_of_frames == static_cast<size_t>(sample_rate / 100));
xians@webrtc.org56925312014-04-14 10:50:37 +0000167
168 GetPlayoutData(sample_rate, number_of_channels, number_of_frames, false,
wu@webrtc.org94454b72014-06-05 20:34:08 +0000169 audio_data, elapsed_time_ms, ntp_time_ms);
xians@webrtc.org56925312014-04-14 10:50:37 +0000170}
171
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200172int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer) {
173 CriticalSectionScoped cs(&callbackCritSect_);
174 if (voiceEngineObserverPtr_) {
175 shared_->SetLastError(
176 VE_INVALID_OPERATION, kTraceError,
177 "RegisterVoiceEngineObserver() observer already enabled");
178 return -1;
179 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000180
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200181 // Register the observer in all active channels
182 for (voe::ChannelManager::Iterator it(&shared_->channel_manager());
183 it.IsValid(); it.Increment()) {
184 it.GetChannel()->RegisterVoiceEngineObserver(observer);
185 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000186
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200187 shared_->transmit_mixer()->RegisterVoiceEngineObserver(observer);
188 voiceEngineObserverPtr_ = &observer;
189 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000190}
191
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200192int VoEBaseImpl::DeRegisterVoiceEngineObserver() {
193 CriticalSectionScoped cs(&callbackCritSect_);
194 if (!voiceEngineObserverPtr_) {
195 shared_->SetLastError(
196 VE_INVALID_OPERATION, kTraceError,
197 "DeRegisterVoiceEngineObserver() observer already disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000198 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200199 }
200 voiceEngineObserverPtr_ = nullptr;
201
202 // Deregister the observer in all active channels
203 for (voe::ChannelManager::Iterator it(&shared_->channel_manager());
204 it.IsValid(); it.Increment()) {
205 it.GetChannel()->DeRegisterVoiceEngineObserver();
206 }
207
208 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000209}
210
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000211int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200212 AudioProcessing* audioproc) {
213 CriticalSectionScoped cs(shared_->crit_sec());
214 WebRtcSpl_Init();
215 if (shared_->statistics().Initialized()) {
216 return 0;
217 }
218 if (shared_->process_thread()) {
219 shared_->process_thread()->Start();
220 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000221
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200222 // Create an internal ADM if the user has not added an external
223 // ADM implementation as input to Init().
224 if (external_adm == nullptr) {
Tommi931e6582015-05-20 09:44:38 +0200225#if !defined(WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE)
226 return -1;
227#else
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200228 // Create the internal ADM implementation.
229 shared_->set_audio_device(AudioDeviceModuleImpl::Create(
230 VoEId(shared_->instance_id(), -1), shared_->audio_device_layer()));
kma@webrtc.org0221b782012-09-08 00:09:26 +0000231
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200232 if (shared_->audio_device() == nullptr) {
233 shared_->SetLastError(VE_NO_MEMORY, kTraceCritical,
234 "Init() failed to create the ADM");
235 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000236 }
Tommi931e6582015-05-20 09:44:38 +0200237#endif // WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200238 } else {
239 // Use the already existing external ADM implementation.
240 shared_->set_audio_device(external_adm);
241 LOG_F(LS_INFO)
242 << "An external ADM implementation will be used in VoiceEngine";
243 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000244
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200245 // Register the ADM to the process thread, which will drive the error
246 // callback mechanism
247 if (shared_->process_thread()) {
248 shared_->process_thread()->RegisterModule(shared_->audio_device());
249 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000250
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200251 bool available = false;
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000252
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200253 // --------------------
254 // Reinitialize the ADM
henrika@google.com73d65512011-09-07 15:11:18 +0000255
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200256 // Register the AudioObserver implementation
257 if (shared_->audio_device()->RegisterEventObserver(this) != 0) {
258 shared_->SetLastError(
259 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
260 "Init() failed to register event observer for the ADM");
261 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000262
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200263 // Register the AudioTransport implementation
264 if (shared_->audio_device()->RegisterAudioCallback(this) != 0) {
265 shared_->SetLastError(
266 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
267 "Init() failed to register audio callback for the ADM");
268 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000269
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200270 // ADM initialization
271 if (shared_->audio_device()->Init() != 0) {
272 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
273 "Init() failed to initialize the ADM");
274 return -1;
275 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000276
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200277 // Initialize the default speaker
278 if (shared_->audio_device()->SetPlayoutDevice(
279 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
280 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
281 "Init() failed to set the default output device");
282 }
283 if (shared_->audio_device()->InitSpeaker() != 0) {
284 shared_->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
285 "Init() failed to initialize the speaker");
286 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000287
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200288 // Initialize the default microphone
289 if (shared_->audio_device()->SetRecordingDevice(
290 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
291 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
292 "Init() failed to set the default input device");
293 }
294 if (shared_->audio_device()->InitMicrophone() != 0) {
295 shared_->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
296 "Init() failed to initialize the microphone");
297 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000298
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200299 // Set number of channels
300 if (shared_->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
301 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
302 "Init() failed to query stereo playout mode");
303 }
304 if (shared_->audio_device()->SetStereoPlayout(available) != 0) {
305 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
306 "Init() failed to set mono/stereo playout mode");
307 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000308
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200309 // TODO(andrew): These functions don't tell us whether stereo recording
310 // is truly available. We simply set the AudioProcessing input to stereo
311 // here, because we have to wait until receiving the first frame to
312 // determine the actual number of channels anyway.
313 //
314 // These functions may be changed; tracked here:
315 // http://code.google.com/p/webrtc/issues/detail?id=204
316 shared_->audio_device()->StereoRecordingIsAvailable(&available);
317 if (shared_->audio_device()->SetStereoRecording(available) != 0) {
318 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
319 "Init() failed to set mono/stereo recording mode");
320 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000321
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200322 if (!audioproc) {
323 audioproc = AudioProcessing::Create();
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000324 if (!audioproc) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200325 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
326 shared_->SetLastError(VE_NO_MEMORY);
327 return -1;
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000328 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200329 }
330 shared_->set_audio_processing(audioproc);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000331
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200332 // Set the error state for any failures in this block.
333 shared_->SetLastError(VE_APM_ERROR);
334 // Configure AudioProcessing components.
335 if (audioproc->high_pass_filter()->Enable(true) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200336 LOG_F(LS_ERROR) << "Failed to enable high pass filter.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200337 return -1;
338 }
339 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200340 LOG_F(LS_ERROR) << "Failed to disable drift compensation.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200341 return -1;
342 }
343 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200344 LOG_F(LS_ERROR) << "Failed to set noise suppression level: "
345 << kDefaultNsMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200346 return -1;
347 }
348 GainControl* agc = audioproc->gain_control();
349 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200350 LOG_F(LS_ERROR) << "Failed to set analog level limits with minimum: "
351 << kMinVolumeLevel << " and maximum: " << kMaxVolumeLevel;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200352 return -1;
353 }
354 if (agc->set_mode(kDefaultAgcMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200355 LOG_F(LS_ERROR) << "Failed to set mode: " << kDefaultAgcMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200356 return -1;
357 }
358 if (agc->Enable(kDefaultAgcState) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200359 LOG_F(LS_ERROR) << "Failed to set agc state: " << kDefaultAgcState;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200360 return -1;
361 }
362 shared_->SetLastError(0); // Clear error state.
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000363
niklase@google.com470e71d2011-07-07 08:21:25 +0000364#ifdef WEBRTC_VOICE_ENGINE_AGC
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200365 bool agc_enabled =
366 agc->mode() == GainControl::kAdaptiveAnalog && agc->is_enabled();
367 if (shared_->audio_device()->SetAGC(agc_enabled) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200368 LOG_F(LS_ERROR) << "Failed to set agc to enabled: " << agc_enabled;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200369 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
370 // TODO(ajm): No error return here due to
371 // https://code.google.com/p/webrtc/issues/detail?id=1464
372 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000373#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000374
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200375 return shared_->statistics().SetInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000376}
377
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200378int VoEBaseImpl::Terminate() {
379 CriticalSectionScoped cs(shared_->crit_sec());
380 return TerminateInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000381}
382
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000383int VoEBaseImpl::CreateChannel() {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200384 CriticalSectionScoped cs(shared_->crit_sec());
385 if (!shared_->statistics().Initialized()) {
386 shared_->SetLastError(VE_NOT_INITED, kTraceError);
387 return -1;
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000388 }
389
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200390 voe::ChannelOwner channel_owner = shared_->channel_manager().CreateChannel();
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000391 return InitializeChannel(&channel_owner);
392}
393
394int VoEBaseImpl::CreateChannel(const Config& config) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200395 CriticalSectionScoped cs(shared_->crit_sec());
396 if (!shared_->statistics().Initialized()) {
397 shared_->SetLastError(VE_NOT_INITED, kTraceError);
398 return -1;
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000399 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200400 voe::ChannelOwner channel_owner =
401 shared_->channel_manager().CreateChannel(config);
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000402 return InitializeChannel(&channel_owner);
403}
404
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200405int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner) {
406 if (channel_owner->channel()->SetEngineInformation(
407 shared_->statistics(), *shared_->output_mixer(),
408 *shared_->transmit_mixer(), *shared_->process_thread(),
409 *shared_->audio_device(), voiceEngineObserverPtr_,
410 &callbackCritSect_) != 0) {
411 shared_->SetLastError(
412 VE_CHANNEL_NOT_CREATED, kTraceError,
413 "CreateChannel() failed to associate engine and channel."
414 " Destroying channel.");
415 shared_->channel_manager().DestroyChannel(
416 channel_owner->channel()->ChannelId());
417 return -1;
418 } else if (channel_owner->channel()->Init() != 0) {
419 shared_->SetLastError(
420 VE_CHANNEL_NOT_CREATED, kTraceError,
421 "CreateChannel() failed to initialize channel. Destroying"
422 " channel.");
423 shared_->channel_manager().DestroyChannel(
424 channel_owner->channel()->ChannelId());
425 return -1;
426 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000427
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200428 return channel_owner->channel()->ChannelId();
niklase@google.com470e71d2011-07-07 08:21:25 +0000429}
430
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200431int VoEBaseImpl::DeleteChannel(int channel) {
432 CriticalSectionScoped cs(shared_->crit_sec());
433 if (!shared_->statistics().Initialized()) {
434 shared_->SetLastError(VE_NOT_INITED, kTraceError);
435 return -1;
436 }
437
438 {
439 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
440 voe::Channel* channelPtr = ch.channel();
441 if (channelPtr == nullptr) {
442 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
443 "DeleteChannel() failed to locate channel");
444 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000445 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200446 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000447
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200448 shared_->channel_manager().DestroyChannel(channel);
449 if (StopSend() != 0) {
450 return -1;
451 }
452 if (StopPlayout() != 0) {
453 return -1;
454 }
455 return 0;
456}
niklase@google.com470e71d2011-07-07 08:21:25 +0000457
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200458int VoEBaseImpl::StartReceive(int channel) {
459 CriticalSectionScoped cs(shared_->crit_sec());
460 if (!shared_->statistics().Initialized()) {
461 shared_->SetLastError(VE_NOT_INITED, kTraceError);
462 return -1;
463 }
464 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
465 voe::Channel* channelPtr = ch.channel();
466 if (channelPtr == nullptr) {
467 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
468 "StartReceive() failed to locate channel");
469 return -1;
470 }
471 return channelPtr->StartReceiving();
472}
niklase@google.com470e71d2011-07-07 08:21:25 +0000473
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200474int VoEBaseImpl::StopReceive(int channel) {
475 CriticalSectionScoped cs(shared_->crit_sec());
476 if (!shared_->statistics().Initialized()) {
477 shared_->SetLastError(VE_NOT_INITED, kTraceError);
478 return -1;
479 }
480 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
481 voe::Channel* channelPtr = ch.channel();
482 if (channelPtr == nullptr) {
483 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
484 "SetLocalReceiver() failed to locate channel");
485 return -1;
486 }
487 return channelPtr->StopReceiving();
488}
niklase@google.com470e71d2011-07-07 08:21:25 +0000489
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200490int VoEBaseImpl::StartPlayout(int channel) {
491 CriticalSectionScoped cs(shared_->crit_sec());
492 if (!shared_->statistics().Initialized()) {
493 shared_->SetLastError(VE_NOT_INITED, kTraceError);
494 return -1;
495 }
496 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
497 voe::Channel* channelPtr = ch.channel();
498 if (channelPtr == nullptr) {
499 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
500 "StartPlayout() failed to locate channel");
501 return -1;
502 }
503 if (channelPtr->Playing()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000504 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200505 }
506 if (StartPlayout() != 0) {
507 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
508 "StartPlayout() failed to start playout");
509 return -1;
510 }
511 return channelPtr->StartPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000512}
513
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200514int VoEBaseImpl::StopPlayout(int channel) {
515 CriticalSectionScoped cs(shared_->crit_sec());
516 if (!shared_->statistics().Initialized()) {
517 shared_->SetLastError(VE_NOT_INITED, kTraceError);
518 return -1;
519 }
520 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
521 voe::Channel* channelPtr = ch.channel();
522 if (channelPtr == nullptr) {
523 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
524 "StopPlayout() failed to locate channel");
525 return -1;
526 }
527 if (channelPtr->StopPlayout() != 0) {
528 LOG_F(LS_WARNING) << "StopPlayout() failed to stop playout for channel "
529 << channel;
530 }
531 return StopPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000532}
533
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200534int VoEBaseImpl::StartSend(int channel) {
535 CriticalSectionScoped cs(shared_->crit_sec());
536 if (!shared_->statistics().Initialized()) {
537 shared_->SetLastError(VE_NOT_INITED, kTraceError);
538 return -1;
539 }
540 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
541 voe::Channel* channelPtr = ch.channel();
542 if (channelPtr == nullptr) {
543 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
544 "StartSend() failed to locate channel");
545 return -1;
546 }
547 if (channelPtr->Sending()) {
548 return 0;
549 }
550 if (StartSend() != 0) {
551 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
552 "StartSend() failed to start recording");
553 return -1;
554 }
555 return channelPtr->StartSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000556}
557
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200558int VoEBaseImpl::StopSend(int channel) {
559 CriticalSectionScoped cs(shared_->crit_sec());
560 if (!shared_->statistics().Initialized()) {
561 shared_->SetLastError(VE_NOT_INITED, kTraceError);
562 return -1;
563 }
564 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
565 voe::Channel* channelPtr = ch.channel();
566 if (channelPtr == nullptr) {
567 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
568 "StopSend() failed to locate channel");
569 return -1;
570 }
571 if (channelPtr->StopSend() != 0) {
572 LOG_F(LS_WARNING) << "StopSend() failed to stop sending for channel "
573 << channel;
574 }
575 return StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000576}
577
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200578int VoEBaseImpl::GetVersion(char version[1024]) {
André Susano Pinto664cdaf2015-05-20 11:11:07 +0200579 static_assert(kVoiceEngineVersionMaxMessageSize == 1024, "");
niklase@google.com470e71d2011-07-07 08:21:25 +0000580
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200581 if (version == nullptr) {
582 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
583 return (-1);
584 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000585
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200586 char versionBuf[kVoiceEngineVersionMaxMessageSize];
587 char* versionPtr = versionBuf;
niklase@google.com470e71d2011-07-07 08:21:25 +0000588
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200589 int32_t len = 0;
590 int32_t accLen = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000591
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200592 len = AddVoEVersion(versionPtr);
593 if (len == -1) {
594 return -1;
595 }
596 versionPtr += len;
597 accLen += len;
598 assert(accLen < kVoiceEngineVersionMaxMessageSize);
niklase@google.com470e71d2011-07-07 08:21:25 +0000599
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000600#ifdef WEBRTC_EXTERNAL_TRANSPORT
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200601 len = AddExternalTransportBuild(versionPtr);
602 if (len == -1) {
603 return -1;
604 }
605 versionPtr += len;
606 accLen += len;
607 assert(accLen < kVoiceEngineVersionMaxMessageSize);
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000608#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000609
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200610 memcpy(version, versionBuf, accLen);
611 version[accLen] = '\0';
niklase@google.com470e71d2011-07-07 08:21:25 +0000612
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200613 // to avoid the truncation in the trace, split the string into parts
614 char partOfVersion[256];
615 for (int partStart = 0; partStart < accLen;) {
616 memset(partOfVersion, 0, sizeof(partOfVersion));
617 int partEnd = partStart + 180;
618 while (version[partEnd] != '\n' && version[partEnd] != '\0') {
619 partEnd--;
niklase@google.com470e71d2011-07-07 08:21:25 +0000620 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200621 if (partEnd < accLen) {
622 memcpy(partOfVersion, &version[partStart], partEnd - partStart);
623 } else {
624 memcpy(partOfVersion, &version[partStart], accLen - partStart);
625 }
626 partStart = partEnd;
627 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000628
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200629 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000630}
631
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200632int32_t VoEBaseImpl::AddVoEVersion(char* str) const {
633 return sprintf(str, "VoiceEngine 4.1.0\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000634}
635
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000636#ifdef WEBRTC_EXTERNAL_TRANSPORT
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200637int32_t VoEBaseImpl::AddExternalTransportBuild(char* str) const {
638 return sprintf(str, "External transport build\n");
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000639}
640#endif
641
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200642int VoEBaseImpl::LastError() { return (shared_->statistics().LastError()); }
niklase@google.com470e71d2011-07-07 08:21:25 +0000643
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200644int32_t VoEBaseImpl::StartPlayout() {
solenberge313e022015-09-08 02:16:04 -0700645 if (!shared_->audio_device()->Playing()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200646 if (shared_->audio_device()->InitPlayout() != 0) {
647 LOG_F(LS_ERROR) << "Failed to initialize playout";
648 return -1;
649 }
650 if (shared_->audio_device()->StartPlayout() != 0) {
651 LOG_F(LS_ERROR) << "Failed to start playout";
652 return -1;
653 }
654 }
655 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000656}
657
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000658int32_t VoEBaseImpl::StopPlayout() {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000659 // Stop audio-device playing if no channel is playing out
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200660 if (shared_->NumOfPlayingChannels() == 0) {
661 if (shared_->audio_device()->StopPlayout() != 0) {
662 shared_->SetLastError(VE_CANNOT_STOP_PLAYOUT, kTraceError,
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000663 "StopPlayout() failed to stop playout");
664 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000665 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000666 }
667 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000668}
669
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200670int32_t VoEBaseImpl::StartSend() {
solenberge313e022015-09-08 02:16:04 -0700671 if (!shared_->audio_device()->Recording()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200672 if (shared_->audio_device()->InitRecording() != 0) {
673 LOG_F(LS_ERROR) << "Failed to initialize recording";
674 return -1;
675 }
676 if (shared_->audio_device()->StartRecording() != 0) {
677 LOG_F(LS_ERROR) << "Failed to start recording";
678 return -1;
679 }
680 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200681 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000682}
683
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200684int32_t VoEBaseImpl::StopSend() {
685 if (shared_->NumOfSendingChannels() == 0 &&
686 !shared_->transmit_mixer()->IsRecordingMic()) {
687 // Stop audio-device recording if no channel is recording
688 if (shared_->audio_device()->StopRecording() != 0) {
689 shared_->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
690 "StopSend() failed to stop recording");
691 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000692 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200693 shared_->transmit_mixer()->StopSend();
694 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000695
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200696 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000697}
698
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200699int32_t VoEBaseImpl::TerminateInternal() {
700 // Delete any remaining channel objects
701 shared_->channel_manager().DestroyAllChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000702
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200703 if (shared_->process_thread()) {
704 if (shared_->audio_device()) {
705 shared_->process_thread()->DeRegisterModule(shared_->audio_device());
niklase@google.com470e71d2011-07-07 08:21:25 +0000706 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200707 shared_->process_thread()->Stop();
708 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000709
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200710 if (shared_->audio_device()) {
711 if (shared_->audio_device()->StopPlayout() != 0) {
712 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
713 "TerminateInternal() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000714 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200715 if (shared_->audio_device()->StopRecording() != 0) {
716 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
717 "TerminateInternal() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000718 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200719 if (shared_->audio_device()->RegisterEventObserver(nullptr) != 0) {
720 shared_->SetLastError(
721 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
722 "TerminateInternal() failed to de-register event observer "
723 "for the ADM");
724 }
725 if (shared_->audio_device()->RegisterAudioCallback(nullptr) != 0) {
726 shared_->SetLastError(
727 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
728 "TerminateInternal() failed to de-register audio callback "
729 "for the ADM");
730 }
731 if (shared_->audio_device()->Terminate() != 0) {
732 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
733 "TerminateInternal() failed to terminate the ADM");
734 }
735 shared_->set_audio_device(nullptr);
736 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000737
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200738 if (shared_->audio_processing()) {
739 shared_->set_audio_processing(nullptr);
740 }
741
742 return shared_->statistics().SetUnInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000743}
744
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000745int VoEBaseImpl::ProcessRecordedDataWithAPM(
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200746 const int voe_channels[], int number_of_voe_channels,
747 const void* audio_data, uint32_t sample_rate, uint8_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700748 size_t number_of_frames, uint32_t audio_delay_milliseconds,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200749 int32_t clock_drift, uint32_t volume, bool key_pressed) {
750 assert(shared_->transmit_mixer() != nullptr);
751 assert(shared_->audio_device() != nullptr);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000752
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000753 uint32_t max_volume = 0;
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000754 uint16_t voe_mic_level = 0;
andrew@webrtc.org023cc5a2014-01-11 01:25:53 +0000755 // Check for zero to skip this calculation; the consumer may use this to
756 // indicate no volume is available.
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000757 if (volume != 0) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000758 // Scale from ADM to VoE level range
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200759 if (shared_->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000760 if (max_volume) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000761 voe_mic_level = static_cast<uint16_t>(
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200762 (volume * kMaxVolumeLevel + static_cast<int>(max_volume / 2)) /
763 max_volume);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000764 }
765 }
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000766 // We learned that on certain systems (e.g Linux) the voe_mic_level
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000767 // can be greater than the maxVolumeLevel therefore
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000768 // we are going to cap the voe_mic_level to the maxVolumeLevel
769 // and change the maxVolume to volume if it turns out that
770 // the voe_mic_level is indeed greater than the maxVolumeLevel.
771 if (voe_mic_level > kMaxVolumeLevel) {
772 voe_mic_level = kMaxVolumeLevel;
773 max_volume = volume;
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000774 }
775 }
776
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000777 // Perform channel-independent operations
778 // (APM, mix with file, record to file, mute, etc.)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200779 shared_->transmit_mixer()->PrepareDemux(
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000780 audio_data, number_of_frames, number_of_channels, sample_rate,
781 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000782 voe_mic_level, key_pressed);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000783
784 // Copy the audio frame to each sending channel and perform
785 // channel-dependent operations (file mixing, mute, etc.), encode and
786 // packetize+transmit the RTP packet. When |number_of_voe_channels| == 0,
787 // do the operations on all the existing VoE channels; otherwise the
788 // operations will be done on specific channels.
789 if (number_of_voe_channels == 0) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200790 shared_->transmit_mixer()->DemuxAndMix();
791 shared_->transmit_mixer()->EncodeAndSend();
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000792 } else {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200793 shared_->transmit_mixer()->DemuxAndMix(voe_channels,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000794 number_of_voe_channels);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200795 shared_->transmit_mixer()->EncodeAndSend(voe_channels,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000796 number_of_voe_channels);
797 }
798
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000799 // Scale from VoE to ADM level range.
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200800 uint32_t new_voe_mic_level = shared_->transmit_mixer()->CaptureLevel();
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000801 if (new_voe_mic_level != voe_mic_level) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000802 // Return the new volume if AGC has changed the volume.
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200803 return static_cast<int>((new_voe_mic_level * max_volume +
804 static_cast<int>(kMaxVolumeLevel / 2)) /
805 kMaxVolumeLevel);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000806 }
807
808 // Return 0 to indicate no change on the volume.
809 return 0;
810}
811
xians@webrtc.org56925312014-04-14 10:50:37 +0000812void VoEBaseImpl::GetPlayoutData(int sample_rate, int number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700813 size_t number_of_frames, bool feed_data_to_apm,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200814 void* audio_data, int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000815 int64_t* ntp_time_ms) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200816 assert(shared_->output_mixer() != nullptr);
xians@webrtc.org56925312014-04-14 10:50:37 +0000817
818 // TODO(andrew): if the device is running in mono, we should tell the mixer
819 // here so that it will only request mono from AudioCodingModule.
820 // Perform mixing of all active participants (channel-based mixing)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200821 shared_->output_mixer()->MixActiveChannels();
xians@webrtc.org56925312014-04-14 10:50:37 +0000822
823 // Additional operations on the combined signal
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200824 shared_->output_mixer()->DoOperationsOnCombinedSignal(feed_data_to_apm);
xians@webrtc.org56925312014-04-14 10:50:37 +0000825
826 // Retrieve the final output mix (resampled to match the ADM)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200827 shared_->output_mixer()->GetMixedAudio(sample_rate, number_of_channels,
828 &audioFrame_);
xians@webrtc.org56925312014-04-14 10:50:37 +0000829
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200830 assert(number_of_frames == audioFrame_.samples_per_channel_);
831 assert(sample_rate == audioFrame_.sample_rate_hz_);
xians@webrtc.org56925312014-04-14 10:50:37 +0000832
833 // Deliver audio (PCM) samples to the ADM
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200834 memcpy(audio_data, audioFrame_.data_,
xians@webrtc.org56925312014-04-14 10:50:37 +0000835 sizeof(int16_t) * number_of_frames * number_of_channels);
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000836
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200837 *elapsed_time_ms = audioFrame_.elapsed_time_ms_;
838 *ntp_time_ms = audioFrame_.ntp_time_ms_;
xians@webrtc.org56925312014-04-14 10:50:37 +0000839}
840
Minyue2013aec2015-05-13 14:14:42 +0200841int VoEBaseImpl::AssociateSendChannel(int channel,
842 int accociate_send_channel) {
843 CriticalSectionScoped cs(shared_->crit_sec());
844
845 if (!shared_->statistics().Initialized()) {
846 shared_->SetLastError(VE_NOT_INITED, kTraceError);
847 return -1;
848 }
849
850 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
851 voe::Channel* channel_ptr = ch.channel();
852 if (channel_ptr == NULL) {
853 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
854 "AssociateSendChannel() failed to locate channel");
855 return -1;
856 }
857
858 ch = shared_->channel_manager().GetChannel(accociate_send_channel);
859 voe::Channel* accociate_send_channel_ptr = ch.channel();
860 if (accociate_send_channel_ptr == NULL) {
861 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
862 "AssociateSendChannel() failed to locate accociate_send_channel");
863 return -1;
864 }
865
866 channel_ptr->set_associate_send_channel(ch);
867 return 0;
868}
869
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000870} // namespace webrtc