blob: 677e9b1cf9cf5a7ca2f341938ef7c5fadf3694ed [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"
Henrik Kjellander74640892015-10-29 11:31:02 +010016#include "webrtc/modules/audio_coding/main/include/audio_coding_module.h"
pbos@webrtc.org956aa7e2013-05-21 13:52:32 +000017#include "webrtc/modules/audio_device/audio_device_impl.h"
18#include "webrtc/modules/audio_processing/include/audio_processing.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010019#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
20#include "webrtc/system_wrappers/include/file_wrapper.h"
21#include "webrtc/system_wrappers/include/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
solenberg13725082015-11-25 08:16:52 -080050void VoEBaseImpl::OnErrorIsReported(const ErrorCode error) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +020051 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
solenberg13725082015-11-25 08:16:52 -080066void VoEBaseImpl::OnWarningIsReported(const WarningCode warning) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +020067 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
solenberg13725082015-11-25 08:16:52 -080082int32_t VoEBaseImpl::RecordedDataIsAvailable(const void* audioSamples,
83 const size_t nSamples,
84 const size_t nBytesPerSample,
85 const uint8_t nChannels,
86 const uint32_t samplesPerSec,
87 const uint32_t totalDelayMS,
88 const int32_t clockDrift,
89 const uint32_t currentMicLevel,
90 const bool keyPressed,
91 uint32_t& newMicLevel) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +020092 newMicLevel = static_cast<uint32_t>(ProcessRecordedDataWithAPM(
93 nullptr, 0, audioSamples, samplesPerSec, nChannels, nSamples,
solenberg13725082015-11-25 08:16:52 -080094 totalDelayMS, clockDrift, currentMicLevel, keyPressed));
Jelena Marusic2dd6a272015-04-14 09:47:00 +020095 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000096}
97
solenberg13725082015-11-25 08:16:52 -080098int32_t VoEBaseImpl::NeedMorePlayData(const size_t nSamples,
99 const size_t nBytesPerSample,
100 const uint8_t nChannels,
101 const uint32_t samplesPerSec,
102 void* audioSamples,
103 size_t& nSamplesOut,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200104 int64_t* elapsed_time_ms,
105 int64_t* ntp_time_ms) {
106 GetPlayoutData(static_cast<int>(samplesPerSec), static_cast<int>(nChannels),
Peter Kastingdce40cf2015-08-24 14:52:23 -0700107 nSamples, true, audioSamples,
wu@webrtc.org94454b72014-06-05 20:34:08 +0000108 elapsed_time_ms, ntp_time_ms);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200109 nSamplesOut = audioFrame_.samples_per_channel_;
xians@webrtc.org56925312014-04-14 10:50:37 +0000110 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000111}
112
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000113int VoEBaseImpl::OnDataAvailable(const int voe_channels[],
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000114 int number_of_voe_channels,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200115 const int16_t* audio_data, int sample_rate,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700116 int number_of_channels,
117 size_t number_of_frames,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200118 int audio_delay_milliseconds, int volume,
119 bool key_pressed, bool need_audio_processing) {
120 if (number_of_voe_channels == 0) return 0;
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000121
122 if (need_audio_processing) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000123 return ProcessRecordedDataWithAPM(
124 voe_channels, number_of_voe_channels, audio_data, sample_rate,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200125 number_of_channels, number_of_frames, audio_delay_milliseconds, 0,
126 volume, key_pressed);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000127 }
128
129 // No need to go through the APM, demultiplex the data to each VoE channel,
130 // encode and send to the network.
131 for (int i = 0; i < number_of_voe_channels; ++i) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000132 // TODO(ajm): In the case where multiple channels are using the same codec
133 // rate, this path needlessly does extra conversions. We should convert once
134 // and share between channels.
xians@webrtc.org56925312014-04-14 10:50:37 +0000135 PushCaptureData(voe_channels[i], audio_data, 16, sample_rate,
136 number_of_channels, number_of_frames);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000137 }
138
139 // Return 0 to indicate no need to change the volume.
140 return 0;
141}
142
xians@webrtc.orgc1e28032014-02-02 15:30:20 +0000143void VoEBaseImpl::OnData(int voe_channel, const void* audio_data,
144 int bits_per_sample, int sample_rate,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700145 int number_of_channels, size_t number_of_frames) {
xians@webrtc.org56925312014-04-14 10:50:37 +0000146 PushCaptureData(voe_channel, audio_data, bits_per_sample, sample_rate,
147 number_of_channels, number_of_frames);
148}
149
150void VoEBaseImpl::PushCaptureData(int voe_channel, const void* audio_data,
151 int bits_per_sample, int sample_rate,
152 int number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700153 size_t number_of_frames) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200154 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(voe_channel);
xians@webrtc.org07e51962014-01-29 13:54:02 +0000155 voe::Channel* channel_ptr = ch.channel();
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200156 if (!channel_ptr) return;
xians@webrtc.org07e51962014-01-29 13:54:02 +0000157
henrika@webrtc.org66803482014-04-17 10:45:01 +0000158 if (channel_ptr->Sending()) {
xians@webrtc.org07e51962014-01-29 13:54:02 +0000159 channel_ptr->Demultiplex(static_cast<const int16_t*>(audio_data),
160 sample_rate, number_of_frames, number_of_channels);
161 channel_ptr->PrepareEncodeAndSend(sample_rate);
162 channel_ptr->EncodeAndSend();
163 }
164}
165
Peter Kastingdce40cf2015-08-24 14:52:23 -0700166void VoEBaseImpl::PullRenderData(int bits_per_sample,
167 int sample_rate,
168 int number_of_channels,
169 size_t number_of_frames,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200170 void* audio_data, int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000171 int64_t* ntp_time_ms) {
Jelena Marusic6fc2d2f2015-04-13 14:07:04 +0200172 assert(bits_per_sample == 16);
Peter Kastingdce40cf2015-08-24 14:52:23 -0700173 assert(number_of_frames == static_cast<size_t>(sample_rate / 100));
xians@webrtc.org56925312014-04-14 10:50:37 +0000174
175 GetPlayoutData(sample_rate, number_of_channels, number_of_frames, false,
wu@webrtc.org94454b72014-06-05 20:34:08 +0000176 audio_data, elapsed_time_ms, ntp_time_ms);
xians@webrtc.org56925312014-04-14 10:50:37 +0000177}
178
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200179int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer) {
180 CriticalSectionScoped cs(&callbackCritSect_);
181 if (voiceEngineObserverPtr_) {
182 shared_->SetLastError(
183 VE_INVALID_OPERATION, kTraceError,
184 "RegisterVoiceEngineObserver() observer already enabled");
185 return -1;
186 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000187
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200188 // Register the observer in all active channels
189 for (voe::ChannelManager::Iterator it(&shared_->channel_manager());
190 it.IsValid(); it.Increment()) {
191 it.GetChannel()->RegisterVoiceEngineObserver(observer);
192 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000193
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200194 shared_->transmit_mixer()->RegisterVoiceEngineObserver(observer);
195 voiceEngineObserverPtr_ = &observer;
196 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000197}
198
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200199int VoEBaseImpl::DeRegisterVoiceEngineObserver() {
200 CriticalSectionScoped cs(&callbackCritSect_);
201 if (!voiceEngineObserverPtr_) {
202 shared_->SetLastError(
203 VE_INVALID_OPERATION, kTraceError,
204 "DeRegisterVoiceEngineObserver() observer already disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000205 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200206 }
207 voiceEngineObserverPtr_ = nullptr;
208
209 // Deregister the observer in all active channels
210 for (voe::ChannelManager::Iterator it(&shared_->channel_manager());
211 it.IsValid(); it.Increment()) {
212 it.GetChannel()->DeRegisterVoiceEngineObserver();
213 }
214
215 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000216}
217
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000218int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200219 AudioProcessing* audioproc) {
220 CriticalSectionScoped cs(shared_->crit_sec());
221 WebRtcSpl_Init();
222 if (shared_->statistics().Initialized()) {
223 return 0;
224 }
225 if (shared_->process_thread()) {
226 shared_->process_thread()->Start();
227 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000228
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200229 // Create an internal ADM if the user has not added an external
230 // ADM implementation as input to Init().
231 if (external_adm == nullptr) {
Tommi931e6582015-05-20 09:44:38 +0200232#if !defined(WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE)
233 return -1;
234#else
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200235 // Create the internal ADM implementation.
236 shared_->set_audio_device(AudioDeviceModuleImpl::Create(
237 VoEId(shared_->instance_id(), -1), shared_->audio_device_layer()));
kma@webrtc.org0221b782012-09-08 00:09:26 +0000238
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200239 if (shared_->audio_device() == nullptr) {
240 shared_->SetLastError(VE_NO_MEMORY, kTraceCritical,
241 "Init() failed to create the ADM");
242 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000243 }
Tommi931e6582015-05-20 09:44:38 +0200244#endif // WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200245 } else {
246 // Use the already existing external ADM implementation.
247 shared_->set_audio_device(external_adm);
248 LOG_F(LS_INFO)
249 << "An external ADM implementation will be used in VoiceEngine";
250 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000251
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200252 // Register the ADM to the process thread, which will drive the error
253 // callback mechanism
254 if (shared_->process_thread()) {
255 shared_->process_thread()->RegisterModule(shared_->audio_device());
256 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000257
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200258 bool available = false;
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000259
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200260 // --------------------
261 // Reinitialize the ADM
henrika@google.com73d65512011-09-07 15:11:18 +0000262
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200263 // Register the AudioObserver implementation
264 if (shared_->audio_device()->RegisterEventObserver(this) != 0) {
265 shared_->SetLastError(
266 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
267 "Init() failed to register event observer for the ADM");
268 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000269
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200270 // Register the AudioTransport implementation
271 if (shared_->audio_device()->RegisterAudioCallback(this) != 0) {
272 shared_->SetLastError(
273 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
274 "Init() failed to register audio callback for the ADM");
275 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000276
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200277 // ADM initialization
278 if (shared_->audio_device()->Init() != 0) {
279 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
280 "Init() failed to initialize the ADM");
281 return -1;
282 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000283
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200284 // Initialize the default speaker
285 if (shared_->audio_device()->SetPlayoutDevice(
286 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
287 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
288 "Init() failed to set the default output device");
289 }
290 if (shared_->audio_device()->InitSpeaker() != 0) {
291 shared_->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
292 "Init() failed to initialize the speaker");
293 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000294
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200295 // Initialize the default microphone
296 if (shared_->audio_device()->SetRecordingDevice(
297 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
298 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
299 "Init() failed to set the default input device");
300 }
301 if (shared_->audio_device()->InitMicrophone() != 0) {
302 shared_->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
303 "Init() failed to initialize the microphone");
304 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000305
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200306 // Set number of channels
307 if (shared_->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
308 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
309 "Init() failed to query stereo playout mode");
310 }
311 if (shared_->audio_device()->SetStereoPlayout(available) != 0) {
312 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
313 "Init() failed to set mono/stereo playout mode");
314 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000315
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200316 // TODO(andrew): These functions don't tell us whether stereo recording
317 // is truly available. We simply set the AudioProcessing input to stereo
318 // here, because we have to wait until receiving the first frame to
319 // determine the actual number of channels anyway.
320 //
321 // These functions may be changed; tracked here:
322 // http://code.google.com/p/webrtc/issues/detail?id=204
323 shared_->audio_device()->StereoRecordingIsAvailable(&available);
324 if (shared_->audio_device()->SetStereoRecording(available) != 0) {
325 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
326 "Init() failed to set mono/stereo recording mode");
327 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000328
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200329 if (!audioproc) {
330 audioproc = AudioProcessing::Create();
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000331 if (!audioproc) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200332 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
333 shared_->SetLastError(VE_NO_MEMORY);
334 return -1;
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000335 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200336 }
337 shared_->set_audio_processing(audioproc);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000338
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200339 // Set the error state for any failures in this block.
340 shared_->SetLastError(VE_APM_ERROR);
341 // Configure AudioProcessing components.
342 if (audioproc->high_pass_filter()->Enable(true) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200343 LOG_F(LS_ERROR) << "Failed to enable high pass filter.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200344 return -1;
345 }
346 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200347 LOG_F(LS_ERROR) << "Failed to disable drift compensation.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200348 return -1;
349 }
350 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200351 LOG_F(LS_ERROR) << "Failed to set noise suppression level: "
352 << kDefaultNsMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200353 return -1;
354 }
355 GainControl* agc = audioproc->gain_control();
356 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200357 LOG_F(LS_ERROR) << "Failed to set analog level limits with minimum: "
358 << kMinVolumeLevel << " and maximum: " << kMaxVolumeLevel;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200359 return -1;
360 }
361 if (agc->set_mode(kDefaultAgcMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200362 LOG_F(LS_ERROR) << "Failed to set mode: " << kDefaultAgcMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200363 return -1;
364 }
365 if (agc->Enable(kDefaultAgcState) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200366 LOG_F(LS_ERROR) << "Failed to set agc state: " << kDefaultAgcState;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200367 return -1;
368 }
369 shared_->SetLastError(0); // Clear error state.
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000370
niklase@google.com470e71d2011-07-07 08:21:25 +0000371#ifdef WEBRTC_VOICE_ENGINE_AGC
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200372 bool agc_enabled =
373 agc->mode() == GainControl::kAdaptiveAnalog && agc->is_enabled();
374 if (shared_->audio_device()->SetAGC(agc_enabled) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200375 LOG_F(LS_ERROR) << "Failed to set agc to enabled: " << agc_enabled;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200376 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
377 // TODO(ajm): No error return here due to
378 // https://code.google.com/p/webrtc/issues/detail?id=1464
379 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000380#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000381
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200382 return shared_->statistics().SetInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000383}
384
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200385int VoEBaseImpl::Terminate() {
386 CriticalSectionScoped cs(shared_->crit_sec());
387 return TerminateInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000388}
389
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000390int VoEBaseImpl::CreateChannel() {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200391 CriticalSectionScoped cs(shared_->crit_sec());
392 if (!shared_->statistics().Initialized()) {
393 shared_->SetLastError(VE_NOT_INITED, kTraceError);
394 return -1;
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000395 }
396
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200397 voe::ChannelOwner channel_owner = shared_->channel_manager().CreateChannel();
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000398 return InitializeChannel(&channel_owner);
399}
400
401int VoEBaseImpl::CreateChannel(const Config& config) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200402 CriticalSectionScoped cs(shared_->crit_sec());
403 if (!shared_->statistics().Initialized()) {
404 shared_->SetLastError(VE_NOT_INITED, kTraceError);
405 return -1;
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000406 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200407 voe::ChannelOwner channel_owner =
408 shared_->channel_manager().CreateChannel(config);
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000409 return InitializeChannel(&channel_owner);
410}
411
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200412int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner) {
413 if (channel_owner->channel()->SetEngineInformation(
414 shared_->statistics(), *shared_->output_mixer(),
415 *shared_->transmit_mixer(), *shared_->process_thread(),
416 *shared_->audio_device(), voiceEngineObserverPtr_,
417 &callbackCritSect_) != 0) {
418 shared_->SetLastError(
419 VE_CHANNEL_NOT_CREATED, kTraceError,
420 "CreateChannel() failed to associate engine and channel."
421 " Destroying channel.");
422 shared_->channel_manager().DestroyChannel(
423 channel_owner->channel()->ChannelId());
424 return -1;
425 } else if (channel_owner->channel()->Init() != 0) {
426 shared_->SetLastError(
427 VE_CHANNEL_NOT_CREATED, kTraceError,
428 "CreateChannel() failed to initialize channel. Destroying"
429 " channel.");
430 shared_->channel_manager().DestroyChannel(
431 channel_owner->channel()->ChannelId());
432 return -1;
433 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200434 return channel_owner->channel()->ChannelId();
niklase@google.com470e71d2011-07-07 08:21:25 +0000435}
436
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200437int VoEBaseImpl::DeleteChannel(int channel) {
438 CriticalSectionScoped cs(shared_->crit_sec());
439 if (!shared_->statistics().Initialized()) {
440 shared_->SetLastError(VE_NOT_INITED, kTraceError);
441 return -1;
442 }
443
444 {
445 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
446 voe::Channel* channelPtr = ch.channel();
447 if (channelPtr == nullptr) {
448 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
449 "DeleteChannel() failed to locate channel");
450 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000451 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200452 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000453
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200454 shared_->channel_manager().DestroyChannel(channel);
455 if (StopSend() != 0) {
456 return -1;
457 }
458 if (StopPlayout() != 0) {
459 return -1;
460 }
461 return 0;
462}
niklase@google.com470e71d2011-07-07 08:21:25 +0000463
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200464int VoEBaseImpl::StartReceive(int channel) {
465 CriticalSectionScoped cs(shared_->crit_sec());
466 if (!shared_->statistics().Initialized()) {
467 shared_->SetLastError(VE_NOT_INITED, kTraceError);
468 return -1;
469 }
470 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
471 voe::Channel* channelPtr = ch.channel();
472 if (channelPtr == nullptr) {
473 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
474 "StartReceive() failed to locate channel");
475 return -1;
476 }
477 return channelPtr->StartReceiving();
478}
niklase@google.com470e71d2011-07-07 08:21:25 +0000479
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200480int VoEBaseImpl::StopReceive(int channel) {
481 CriticalSectionScoped cs(shared_->crit_sec());
482 if (!shared_->statistics().Initialized()) {
483 shared_->SetLastError(VE_NOT_INITED, kTraceError);
484 return -1;
485 }
486 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
487 voe::Channel* channelPtr = ch.channel();
488 if (channelPtr == nullptr) {
489 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
490 "SetLocalReceiver() failed to locate channel");
491 return -1;
492 }
493 return channelPtr->StopReceiving();
494}
niklase@google.com470e71d2011-07-07 08:21:25 +0000495
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200496int VoEBaseImpl::StartPlayout(int channel) {
497 CriticalSectionScoped cs(shared_->crit_sec());
498 if (!shared_->statistics().Initialized()) {
499 shared_->SetLastError(VE_NOT_INITED, kTraceError);
500 return -1;
501 }
502 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
503 voe::Channel* channelPtr = ch.channel();
504 if (channelPtr == nullptr) {
505 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
506 "StartPlayout() failed to locate channel");
507 return -1;
508 }
509 if (channelPtr->Playing()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000510 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200511 }
512 if (StartPlayout() != 0) {
513 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
514 "StartPlayout() failed to start playout");
515 return -1;
516 }
517 return channelPtr->StartPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000518}
519
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200520int VoEBaseImpl::StopPlayout(int channel) {
521 CriticalSectionScoped cs(shared_->crit_sec());
522 if (!shared_->statistics().Initialized()) {
523 shared_->SetLastError(VE_NOT_INITED, kTraceError);
524 return -1;
525 }
526 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
527 voe::Channel* channelPtr = ch.channel();
528 if (channelPtr == nullptr) {
529 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
530 "StopPlayout() failed to locate channel");
531 return -1;
532 }
533 if (channelPtr->StopPlayout() != 0) {
534 LOG_F(LS_WARNING) << "StopPlayout() failed to stop playout for channel "
535 << channel;
536 }
537 return StopPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000538}
539
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200540int VoEBaseImpl::StartSend(int channel) {
541 CriticalSectionScoped cs(shared_->crit_sec());
542 if (!shared_->statistics().Initialized()) {
543 shared_->SetLastError(VE_NOT_INITED, kTraceError);
544 return -1;
545 }
546 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
547 voe::Channel* channelPtr = ch.channel();
548 if (channelPtr == nullptr) {
549 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
550 "StartSend() failed to locate channel");
551 return -1;
552 }
553 if (channelPtr->Sending()) {
554 return 0;
555 }
556 if (StartSend() != 0) {
557 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
558 "StartSend() failed to start recording");
559 return -1;
560 }
561 return channelPtr->StartSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000562}
563
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200564int VoEBaseImpl::StopSend(int channel) {
565 CriticalSectionScoped cs(shared_->crit_sec());
566 if (!shared_->statistics().Initialized()) {
567 shared_->SetLastError(VE_NOT_INITED, kTraceError);
568 return -1;
569 }
570 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
571 voe::Channel* channelPtr = ch.channel();
572 if (channelPtr == nullptr) {
573 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
574 "StopSend() failed to locate channel");
575 return -1;
576 }
577 if (channelPtr->StopSend() != 0) {
578 LOG_F(LS_WARNING) << "StopSend() failed to stop sending for channel "
579 << channel;
580 }
581 return StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000582}
583
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200584int VoEBaseImpl::GetVersion(char version[1024]) {
André Susano Pinto664cdaf2015-05-20 11:11:07 +0200585 static_assert(kVoiceEngineVersionMaxMessageSize == 1024, "");
niklase@google.com470e71d2011-07-07 08:21:25 +0000586
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200587 if (version == nullptr) {
588 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
589 return (-1);
590 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000591
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200592 char versionBuf[kVoiceEngineVersionMaxMessageSize];
593 char* versionPtr = versionBuf;
niklase@google.com470e71d2011-07-07 08:21:25 +0000594
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200595 int32_t len = 0;
596 int32_t accLen = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000597
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200598 len = AddVoEVersion(versionPtr);
599 if (len == -1) {
600 return -1;
601 }
602 versionPtr += len;
603 accLen += len;
604 assert(accLen < kVoiceEngineVersionMaxMessageSize);
niklase@google.com470e71d2011-07-07 08:21:25 +0000605
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000606#ifdef WEBRTC_EXTERNAL_TRANSPORT
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200607 len = AddExternalTransportBuild(versionPtr);
608 if (len == -1) {
609 return -1;
610 }
611 versionPtr += len;
612 accLen += len;
613 assert(accLen < kVoiceEngineVersionMaxMessageSize);
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000614#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000615
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200616 memcpy(version, versionBuf, accLen);
617 version[accLen] = '\0';
niklase@google.com470e71d2011-07-07 08:21:25 +0000618
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200619 // to avoid the truncation in the trace, split the string into parts
620 char partOfVersion[256];
621 for (int partStart = 0; partStart < accLen;) {
622 memset(partOfVersion, 0, sizeof(partOfVersion));
623 int partEnd = partStart + 180;
624 while (version[partEnd] != '\n' && version[partEnd] != '\0') {
625 partEnd--;
niklase@google.com470e71d2011-07-07 08:21:25 +0000626 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200627 if (partEnd < accLen) {
628 memcpy(partOfVersion, &version[partStart], partEnd - partStart);
629 } else {
630 memcpy(partOfVersion, &version[partStart], accLen - partStart);
631 }
632 partStart = partEnd;
633 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000634
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200635 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000636}
637
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200638int32_t VoEBaseImpl::AddVoEVersion(char* str) const {
639 return sprintf(str, "VoiceEngine 4.1.0\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000640}
641
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000642#ifdef WEBRTC_EXTERNAL_TRANSPORT
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200643int32_t VoEBaseImpl::AddExternalTransportBuild(char* str) const {
644 return sprintf(str, "External transport build\n");
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000645}
646#endif
647
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200648int VoEBaseImpl::LastError() { return (shared_->statistics().LastError()); }
niklase@google.com470e71d2011-07-07 08:21:25 +0000649
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200650int32_t VoEBaseImpl::StartPlayout() {
solenberge313e022015-09-08 02:16:04 -0700651 if (!shared_->audio_device()->Playing()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200652 if (shared_->audio_device()->InitPlayout() != 0) {
653 LOG_F(LS_ERROR) << "Failed to initialize playout";
654 return -1;
655 }
656 if (shared_->audio_device()->StartPlayout() != 0) {
657 LOG_F(LS_ERROR) << "Failed to start playout";
658 return -1;
659 }
660 }
661 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000662}
663
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000664int32_t VoEBaseImpl::StopPlayout() {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000665 // Stop audio-device playing if no channel is playing out
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200666 if (shared_->NumOfPlayingChannels() == 0) {
667 if (shared_->audio_device()->StopPlayout() != 0) {
668 shared_->SetLastError(VE_CANNOT_STOP_PLAYOUT, kTraceError,
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000669 "StopPlayout() failed to stop playout");
670 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000671 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000672 }
673 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000674}
675
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200676int32_t VoEBaseImpl::StartSend() {
solenberge313e022015-09-08 02:16:04 -0700677 if (!shared_->audio_device()->Recording()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200678 if (shared_->audio_device()->InitRecording() != 0) {
679 LOG_F(LS_ERROR) << "Failed to initialize recording";
680 return -1;
681 }
682 if (shared_->audio_device()->StartRecording() != 0) {
683 LOG_F(LS_ERROR) << "Failed to start recording";
684 return -1;
685 }
686 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200687 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000688}
689
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200690int32_t VoEBaseImpl::StopSend() {
691 if (shared_->NumOfSendingChannels() == 0 &&
692 !shared_->transmit_mixer()->IsRecordingMic()) {
693 // Stop audio-device recording if no channel is recording
694 if (shared_->audio_device()->StopRecording() != 0) {
695 shared_->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
696 "StopSend() failed to stop recording");
697 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000698 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200699 shared_->transmit_mixer()->StopSend();
700 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000701
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200702 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000703}
704
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200705int32_t VoEBaseImpl::TerminateInternal() {
706 // Delete any remaining channel objects
707 shared_->channel_manager().DestroyAllChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000708
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200709 if (shared_->process_thread()) {
710 if (shared_->audio_device()) {
711 shared_->process_thread()->DeRegisterModule(shared_->audio_device());
niklase@google.com470e71d2011-07-07 08:21:25 +0000712 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200713 shared_->process_thread()->Stop();
714 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000715
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200716 if (shared_->audio_device()) {
717 if (shared_->audio_device()->StopPlayout() != 0) {
718 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
719 "TerminateInternal() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000720 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200721 if (shared_->audio_device()->StopRecording() != 0) {
722 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
723 "TerminateInternal() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000724 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200725 if (shared_->audio_device()->RegisterEventObserver(nullptr) != 0) {
726 shared_->SetLastError(
727 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
728 "TerminateInternal() failed to de-register event observer "
729 "for the ADM");
730 }
731 if (shared_->audio_device()->RegisterAudioCallback(nullptr) != 0) {
732 shared_->SetLastError(
733 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
734 "TerminateInternal() failed to de-register audio callback "
735 "for the ADM");
736 }
737 if (shared_->audio_device()->Terminate() != 0) {
738 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
739 "TerminateInternal() failed to terminate the ADM");
740 }
741 shared_->set_audio_device(nullptr);
742 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000743
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200744 if (shared_->audio_processing()) {
745 shared_->set_audio_processing(nullptr);
746 }
747
748 return shared_->statistics().SetUnInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000749}
750
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000751int VoEBaseImpl::ProcessRecordedDataWithAPM(
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200752 const int voe_channels[], int number_of_voe_channels,
753 const void* audio_data, uint32_t sample_rate, uint8_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700754 size_t number_of_frames, uint32_t audio_delay_milliseconds,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200755 int32_t clock_drift, uint32_t volume, bool key_pressed) {
756 assert(shared_->transmit_mixer() != nullptr);
757 assert(shared_->audio_device() != nullptr);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000758
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000759 uint32_t max_volume = 0;
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000760 uint16_t voe_mic_level = 0;
andrew@webrtc.org023cc5a2014-01-11 01:25:53 +0000761 // Check for zero to skip this calculation; the consumer may use this to
762 // indicate no volume is available.
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000763 if (volume != 0) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000764 // Scale from ADM to VoE level range
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200765 if (shared_->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000766 if (max_volume) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000767 voe_mic_level = static_cast<uint16_t>(
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200768 (volume * kMaxVolumeLevel + static_cast<int>(max_volume / 2)) /
769 max_volume);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000770 }
771 }
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000772 // We learned that on certain systems (e.g Linux) the voe_mic_level
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000773 // can be greater than the maxVolumeLevel therefore
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000774 // we are going to cap the voe_mic_level to the maxVolumeLevel
775 // and change the maxVolume to volume if it turns out that
776 // the voe_mic_level is indeed greater than the maxVolumeLevel.
777 if (voe_mic_level > kMaxVolumeLevel) {
778 voe_mic_level = kMaxVolumeLevel;
779 max_volume = volume;
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000780 }
781 }
782
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000783 // Perform channel-independent operations
784 // (APM, mix with file, record to file, mute, etc.)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200785 shared_->transmit_mixer()->PrepareDemux(
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000786 audio_data, number_of_frames, number_of_channels, sample_rate,
787 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000788 voe_mic_level, key_pressed);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000789
790 // Copy the audio frame to each sending channel and perform
791 // channel-dependent operations (file mixing, mute, etc.), encode and
792 // packetize+transmit the RTP packet. When |number_of_voe_channels| == 0,
793 // do the operations on all the existing VoE channels; otherwise the
794 // operations will be done on specific channels.
795 if (number_of_voe_channels == 0) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200796 shared_->transmit_mixer()->DemuxAndMix();
797 shared_->transmit_mixer()->EncodeAndSend();
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000798 } else {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200799 shared_->transmit_mixer()->DemuxAndMix(voe_channels,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000800 number_of_voe_channels);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200801 shared_->transmit_mixer()->EncodeAndSend(voe_channels,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000802 number_of_voe_channels);
803 }
804
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000805 // Scale from VoE to ADM level range.
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200806 uint32_t new_voe_mic_level = shared_->transmit_mixer()->CaptureLevel();
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000807 if (new_voe_mic_level != voe_mic_level) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000808 // Return the new volume if AGC has changed the volume.
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200809 return static_cast<int>((new_voe_mic_level * max_volume +
810 static_cast<int>(kMaxVolumeLevel / 2)) /
811 kMaxVolumeLevel);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000812 }
813
814 // Return 0 to indicate no change on the volume.
815 return 0;
816}
817
xians@webrtc.org56925312014-04-14 10:50:37 +0000818void VoEBaseImpl::GetPlayoutData(int sample_rate, int number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700819 size_t number_of_frames, bool feed_data_to_apm,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200820 void* audio_data, int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000821 int64_t* ntp_time_ms) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200822 assert(shared_->output_mixer() != nullptr);
xians@webrtc.org56925312014-04-14 10:50:37 +0000823
824 // TODO(andrew): if the device is running in mono, we should tell the mixer
825 // here so that it will only request mono from AudioCodingModule.
826 // Perform mixing of all active participants (channel-based mixing)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200827 shared_->output_mixer()->MixActiveChannels();
xians@webrtc.org56925312014-04-14 10:50:37 +0000828
829 // Additional operations on the combined signal
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200830 shared_->output_mixer()->DoOperationsOnCombinedSignal(feed_data_to_apm);
xians@webrtc.org56925312014-04-14 10:50:37 +0000831
832 // Retrieve the final output mix (resampled to match the ADM)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200833 shared_->output_mixer()->GetMixedAudio(sample_rate, number_of_channels,
834 &audioFrame_);
xians@webrtc.org56925312014-04-14 10:50:37 +0000835
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200836 assert(number_of_frames == audioFrame_.samples_per_channel_);
837 assert(sample_rate == audioFrame_.sample_rate_hz_);
xians@webrtc.org56925312014-04-14 10:50:37 +0000838
839 // Deliver audio (PCM) samples to the ADM
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200840 memcpy(audio_data, audioFrame_.data_,
xians@webrtc.org56925312014-04-14 10:50:37 +0000841 sizeof(int16_t) * number_of_frames * number_of_channels);
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000842
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200843 *elapsed_time_ms = audioFrame_.elapsed_time_ms_;
844 *ntp_time_ms = audioFrame_.ntp_time_ms_;
xians@webrtc.org56925312014-04-14 10:50:37 +0000845}
846
Minyue2013aec2015-05-13 14:14:42 +0200847int VoEBaseImpl::AssociateSendChannel(int channel,
848 int accociate_send_channel) {
849 CriticalSectionScoped cs(shared_->crit_sec());
850
851 if (!shared_->statistics().Initialized()) {
852 shared_->SetLastError(VE_NOT_INITED, kTraceError);
853 return -1;
854 }
855
856 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
857 voe::Channel* channel_ptr = ch.channel();
858 if (channel_ptr == NULL) {
859 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
860 "AssociateSendChannel() failed to locate channel");
861 return -1;
862 }
863
864 ch = shared_->channel_manager().GetChannel(accociate_send_channel);
865 voe::Channel* accociate_send_channel_ptr = ch.channel();
866 if (accociate_send_channel_ptr == NULL) {
867 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
868 "AssociateSendChannel() failed to locate accociate_send_channel");
869 return -1;
870 }
871
872 channel_ptr->set_associate_send_channel(ch);
873 return 0;
874}
875
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000876} // namespace webrtc