blob: 30842c5e41d4aed438194bf6a6cde9caadd0279a [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "voice_engine/voe_base_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "api/audio_codecs/builtin_audio_decoder_factory.h"
14#include "common_audio/signal_processing/include/signal_processing_library.h"
15#include "modules/audio_coding/include/audio_coding_module.h"
16#include "modules/audio_device/audio_device_impl.h"
17#include "modules/audio_processing/include/audio_processing.h"
18#include "rtc_base/format_macros.h"
19#include "rtc_base/location.h"
20#include "rtc_base/logging.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "voice_engine/channel.h"
22#include "voice_engine/include/voe_errors.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "voice_engine/transmit_mixer.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "voice_engine/voice_engine_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000025
Jelena Marusic2dd6a272015-04-14 09:47:00 +020026namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000027
Jelena Marusic2dd6a272015-04-14 09:47:00 +020028VoEBase* VoEBase::GetInterface(VoiceEngine* voiceEngine) {
29 if (nullptr == voiceEngine) {
30 return nullptr;
31 }
32 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
33 s->AddRef();
34 return s;
niklase@google.com470e71d2011-07-07 08:21:25 +000035}
36
Jelena Marusic2dd6a272015-04-14 09:47:00 +020037VoEBaseImpl::VoEBaseImpl(voe::SharedData* shared)
solenbergfc3a2e32017-09-26 09:35:01 -070038 : shared_(shared) {}
Jelena Marusic2dd6a272015-04-14 09:47:00 +020039
40VoEBaseImpl::~VoEBaseImpl() {
41 TerminateInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +000042}
43
solenberg13725082015-11-25 08:16:52 -080044void VoEBaseImpl::OnErrorIsReported(const ErrorCode error) {
tommi31fc21f2016-01-21 10:37:37 -080045 rtc::CritScope cs(&callbackCritSect_);
Jelena Marusic2dd6a272015-04-14 09:47:00 +020046 if (error == AudioDeviceObserver::kRecordingError) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +020047 LOG_F(LS_ERROR) << "VE_RUNTIME_REC_ERROR";
48 } else if (error == AudioDeviceObserver::kPlayoutError) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +020049 LOG_F(LS_ERROR) << "VE_RUNTIME_PLAY_ERROR";
50 }
niklase@google.com470e71d2011-07-07 08:21:25 +000051}
52
solenberg13725082015-11-25 08:16:52 -080053void VoEBaseImpl::OnWarningIsReported(const WarningCode warning) {
tommi31fc21f2016-01-21 10:37:37 -080054 rtc::CritScope cs(&callbackCritSect_);
Jelena Marusic2dd6a272015-04-14 09:47:00 +020055 if (warning == AudioDeviceObserver::kRecordingWarning) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +020056 LOG_F(LS_WARNING) << "VE_RUNTIME_REC_WARNING";
57 } else if (warning == AudioDeviceObserver::kPlayoutWarning) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +020058 LOG_F(LS_WARNING) << "VE_RUNTIME_PLAY_WARNING";
59 }
niklase@google.com470e71d2011-07-07 08:21:25 +000060}
61
henrikaec6fbd22017-03-31 05:43:36 -070062int32_t VoEBaseImpl::RecordedDataIsAvailable(
63 const void* audio_data,
64 const size_t number_of_frames,
65 const size_t bytes_per_sample,
66 const size_t number_of_channels,
67 const uint32_t sample_rate,
68 const uint32_t audio_delay_milliseconds,
69 const int32_t clock_drift,
70 const uint32_t volume,
71 const bool key_pressed,
72 uint32_t& new_mic_volume) {
73 RTC_DCHECK_EQ(2 * number_of_channels, bytes_per_sample);
74 RTC_DCHECK(shared_->transmit_mixer() != nullptr);
75 RTC_DCHECK(shared_->audio_device() != nullptr);
76
77 uint32_t max_volume = 0;
78 uint16_t voe_mic_level = 0;
79 // Check for zero to skip this calculation; the consumer may use this to
80 // indicate no volume is available.
81 if (volume != 0) {
82 // Scale from ADM to VoE level range
83 if (shared_->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
84 if (max_volume) {
85 voe_mic_level = static_cast<uint16_t>(
86 (volume * kMaxVolumeLevel + static_cast<int>(max_volume / 2)) /
87 max_volume);
88 }
89 }
90 // We learned that on certain systems (e.g Linux) the voe_mic_level
91 // can be greater than the maxVolumeLevel therefore
92 // we are going to cap the voe_mic_level to the maxVolumeLevel
93 // and change the maxVolume to volume if it turns out that
94 // the voe_mic_level is indeed greater than the maxVolumeLevel.
95 if (voe_mic_level > kMaxVolumeLevel) {
96 voe_mic_level = kMaxVolumeLevel;
97 max_volume = volume;
98 }
99 }
100
101 // Perform channel-independent operations
102 // (APM, mix with file, record to file, mute, etc.)
103 shared_->transmit_mixer()->PrepareDemux(
104 audio_data, number_of_frames, number_of_channels, sample_rate,
105 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
106 voe_mic_level, key_pressed);
107
108 // Copy the audio frame to each sending channel and perform
109 // channel-dependent operations (file mixing, mute, etc.), encode and
110 // packetize+transmit the RTP packet.
111 shared_->transmit_mixer()->ProcessAndEncodeAudio();
112
113 // Scale from VoE to ADM level range.
114 uint32_t new_voe_mic_level = shared_->transmit_mixer()->CaptureLevel();
115 if (new_voe_mic_level != voe_mic_level) {
116 // Return the new volume if AGC has changed the volume.
117 return static_cast<int>((new_voe_mic_level * max_volume +
118 static_cast<int>(kMaxVolumeLevel / 2)) /
119 kMaxVolumeLevel);
120 }
121
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200122 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000123}
124
solenberg13725082015-11-25 08:16:52 -0800125int32_t VoEBaseImpl::NeedMorePlayData(const size_t nSamples,
126 const size_t nBytesPerSample,
Peter Kasting69558702016-01-12 16:26:35 -0800127 const size_t nChannels,
solenberg13725082015-11-25 08:16:52 -0800128 const uint32_t samplesPerSec,
129 void* audioSamples,
130 size_t& nSamplesOut,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200131 int64_t* elapsed_time_ms,
132 int64_t* ntp_time_ms) {
solenberg2397b9a2017-09-22 06:48:10 -0700133 RTC_NOTREACHED();
xians@webrtc.org56925312014-04-14 10:50:37 +0000134 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000135}
136
xians@webrtc.org56925312014-04-14 10:50:37 +0000137void VoEBaseImpl::PushCaptureData(int voe_channel, const void* audio_data,
138 int bits_per_sample, int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800139 size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700140 size_t number_of_frames) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200141 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(voe_channel);
henrikaec6fbd22017-03-31 05:43:36 -0700142 voe::Channel* channel = ch.channel();
143 if (!channel)
144 return;
145 if (channel->Sending()) {
146 // Send the audio to each channel directly without using the APM in the
147 // transmit mixer.
148 channel->ProcessAndEncodeAudio(static_cast<const int16_t*>(audio_data),
149 sample_rate, number_of_frames,
150 number_of_channels);
xians@webrtc.org07e51962014-01-29 13:54:02 +0000151 }
152}
153
Peter Kastingdce40cf2015-08-24 14:52:23 -0700154void VoEBaseImpl::PullRenderData(int bits_per_sample,
155 int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800156 size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700157 size_t number_of_frames,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200158 void* audio_data, int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000159 int64_t* ntp_time_ms) {
solenberg2397b9a2017-09-22 06:48:10 -0700160 RTC_NOTREACHED();
xians@webrtc.org56925312014-04-14 10:50:37 +0000161}
162
ossu5f7cfa52016-05-30 08:11:28 -0700163int VoEBaseImpl::Init(
164 AudioDeviceModule* external_adm,
peahe67bedb2017-07-07 04:25:11 -0700165 AudioProcessing* audio_processing,
ossu5f7cfa52016-05-30 08:11:28 -0700166 const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory) {
peahe67bedb2017-07-07 04:25:11 -0700167 RTC_DCHECK(audio_processing);
tommi31fc21f2016-01-21 10:37:37 -0800168 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200169 WebRtcSpl_Init();
170 if (shared_->statistics().Initialized()) {
171 return 0;
172 }
173 if (shared_->process_thread()) {
174 shared_->process_thread()->Start();
175 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000176
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200177 // Create an internal ADM if the user has not added an external
178 // ADM implementation as input to Init().
179 if (external_adm == nullptr) {
Tommi931e6582015-05-20 09:44:38 +0200180#if !defined(WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE)
181 return -1;
182#else
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200183 // Create the internal ADM implementation.
Peter Boström4adbbcf2016-05-03 15:51:26 -0400184 shared_->set_audio_device(AudioDeviceModule::Create(
solenberg5b3e49a2017-03-15 08:08:07 -0700185 VoEId(shared_->instance_id(), -1),
186 AudioDeviceModule::kPlatformDefaultAudio));
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200187 if (shared_->audio_device() == nullptr) {
188 shared_->SetLastError(VE_NO_MEMORY, kTraceCritical,
189 "Init() failed to create the ADM");
190 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000191 }
Tommi931e6582015-05-20 09:44:38 +0200192#endif // WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200193 } else {
194 // Use the already existing external ADM implementation.
195 shared_->set_audio_device(external_adm);
196 LOG_F(LS_INFO)
197 << "An external ADM implementation will be used in VoiceEngine";
198 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000199
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200200 // Register the ADM to the process thread, which will drive the error
201 // callback mechanism
202 if (shared_->process_thread()) {
tommidea489f2017-03-03 03:20:24 -0800203 shared_->process_thread()->RegisterModule(shared_->audio_device(),
204 RTC_FROM_HERE);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200205 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000206
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200207 bool available = false;
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000208
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200209 // --------------------
210 // Reinitialize the ADM
henrika@google.com73d65512011-09-07 15:11:18 +0000211
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200212 // Register the AudioObserver implementation
213 if (shared_->audio_device()->RegisterEventObserver(this) != 0) {
214 shared_->SetLastError(
215 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
216 "Init() failed to register event observer for the ADM");
217 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000218
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200219 // Register the AudioTransport implementation
220 if (shared_->audio_device()->RegisterAudioCallback(this) != 0) {
221 shared_->SetLastError(
222 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
223 "Init() failed to register audio callback for the ADM");
224 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000225
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200226 // ADM initialization
227 if (shared_->audio_device()->Init() != 0) {
228 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
229 "Init() failed to initialize the ADM");
230 return -1;
231 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000232
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200233 // Initialize the default speaker
234 if (shared_->audio_device()->SetPlayoutDevice(
235 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
236 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
237 "Init() failed to set the default output device");
238 }
239 if (shared_->audio_device()->InitSpeaker() != 0) {
240 shared_->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
241 "Init() failed to initialize the speaker");
242 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000243
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200244 // Initialize the default microphone
245 if (shared_->audio_device()->SetRecordingDevice(
246 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
247 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
248 "Init() failed to set the default input device");
249 }
250 if (shared_->audio_device()->InitMicrophone() != 0) {
251 shared_->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
252 "Init() failed to initialize the microphone");
253 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000254
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200255 // Set number of channels
256 if (shared_->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
257 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
258 "Init() failed to query stereo playout mode");
259 }
260 if (shared_->audio_device()->SetStereoPlayout(available) != 0) {
261 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
262 "Init() failed to set mono/stereo playout mode");
263 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000264
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200265 // TODO(andrew): These functions don't tell us whether stereo recording
266 // is truly available. We simply set the AudioProcessing input to stereo
267 // here, because we have to wait until receiving the first frame to
268 // determine the actual number of channels anyway.
269 //
270 // These functions may be changed; tracked here:
271 // http://code.google.com/p/webrtc/issues/detail?id=204
272 shared_->audio_device()->StereoRecordingIsAvailable(&available);
273 if (shared_->audio_device()->SetStereoRecording(available) != 0) {
274 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
275 "Init() failed to set mono/stereo recording mode");
276 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000277
peahe67bedb2017-07-07 04:25:11 -0700278 shared_->set_audio_processing(audio_processing);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000279
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200280 // Set the error state for any failures in this block.
281 shared_->SetLastError(VE_APM_ERROR);
282 // Configure AudioProcessing components.
peaha9cc40b2017-06-29 08:32:09 -0700283 // TODO(peah): Move this initialization to webrtcvoiceengine.cc.
peahe67bedb2017-07-07 04:25:11 -0700284 if (audio_processing->high_pass_filter()->Enable(true) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200285 LOG_F(LS_ERROR) << "Failed to enable high pass filter.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200286 return -1;
287 }
peahe67bedb2017-07-07 04:25:11 -0700288 if (audio_processing->echo_cancellation()->enable_drift_compensation(false) !=
289 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200290 LOG_F(LS_ERROR) << "Failed to disable drift compensation.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200291 return -1;
292 }
peahe67bedb2017-07-07 04:25:11 -0700293 if (audio_processing->noise_suppression()->set_level(kDefaultNsMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200294 LOG_F(LS_ERROR) << "Failed to set noise suppression level: "
295 << kDefaultNsMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200296 return -1;
297 }
peahe67bedb2017-07-07 04:25:11 -0700298 GainControl* agc = audio_processing->gain_control();
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200299 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200300 LOG_F(LS_ERROR) << "Failed to set analog level limits with minimum: "
301 << kMinVolumeLevel << " and maximum: " << kMaxVolumeLevel;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200302 return -1;
303 }
304 if (agc->set_mode(kDefaultAgcMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200305 LOG_F(LS_ERROR) << "Failed to set mode: " << kDefaultAgcMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200306 return -1;
307 }
308 if (agc->Enable(kDefaultAgcState) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200309 LOG_F(LS_ERROR) << "Failed to set agc state: " << kDefaultAgcState;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200310 return -1;
311 }
312 shared_->SetLastError(0); // Clear error state.
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000313
niklase@google.com470e71d2011-07-07 08:21:25 +0000314#ifdef WEBRTC_VOICE_ENGINE_AGC
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200315 bool agc_enabled =
316 agc->mode() == GainControl::kAdaptiveAnalog && agc->is_enabled();
317 if (shared_->audio_device()->SetAGC(agc_enabled) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200318 LOG_F(LS_ERROR) << "Failed to set agc to enabled: " << agc_enabled;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200319 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
320 // TODO(ajm): No error return here due to
321 // https://code.google.com/p/webrtc/issues/detail?id=1464
322 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000323#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000324
ossu5f7cfa52016-05-30 08:11:28 -0700325 if (decoder_factory)
326 decoder_factory_ = decoder_factory;
327 else
328 decoder_factory_ = CreateBuiltinAudioDecoderFactory();
329
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200330 return shared_->statistics().SetInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000331}
332
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200333int VoEBaseImpl::Terminate() {
tommi31fc21f2016-01-21 10:37:37 -0800334 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200335 return TerminateInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000336}
337
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000338int VoEBaseImpl::CreateChannel() {
solenberg88499ec2016-09-07 07:34:41 -0700339 return CreateChannel(ChannelConfig());
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000340}
341
solenberg88499ec2016-09-07 07:34:41 -0700342int VoEBaseImpl::CreateChannel(const ChannelConfig& config) {
tommi31fc21f2016-01-21 10:37:37 -0800343 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200344 if (!shared_->statistics().Initialized()) {
345 shared_->SetLastError(VE_NOT_INITED, kTraceError);
346 return -1;
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000347 }
solenberg88499ec2016-09-07 07:34:41 -0700348
349 ChannelConfig config_copy(config);
350 config_copy.acm_config.decoder_factory = decoder_factory_;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200351 voe::ChannelOwner channel_owner =
solenberg88499ec2016-09-07 07:34:41 -0700352 shared_->channel_manager().CreateChannel(config_copy);
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000353 return InitializeChannel(&channel_owner);
354}
355
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200356int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner) {
357 if (channel_owner->channel()->SetEngineInformation(
solenberg2397b9a2017-09-22 06:48:10 -0700358 shared_->statistics(),
solenberg796b8f92017-03-01 17:02:23 -0800359 *shared_->process_thread(), *shared_->audio_device(),
solenbergfc3a2e32017-09-26 09:35:01 -0700360 &callbackCritSect_, shared_->encoder_queue()) != 0) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200361 shared_->SetLastError(
362 VE_CHANNEL_NOT_CREATED, kTraceError,
363 "CreateChannel() failed to associate engine and channel."
364 " Destroying channel.");
365 shared_->channel_manager().DestroyChannel(
366 channel_owner->channel()->ChannelId());
367 return -1;
368 } else if (channel_owner->channel()->Init() != 0) {
369 shared_->SetLastError(
370 VE_CHANNEL_NOT_CREATED, kTraceError,
371 "CreateChannel() failed to initialize channel. Destroying"
372 " channel.");
373 shared_->channel_manager().DestroyChannel(
374 channel_owner->channel()->ChannelId());
375 return -1;
376 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200377 return channel_owner->channel()->ChannelId();
niklase@google.com470e71d2011-07-07 08:21:25 +0000378}
379
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200380int VoEBaseImpl::DeleteChannel(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800381 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200382 if (!shared_->statistics().Initialized()) {
383 shared_->SetLastError(VE_NOT_INITED, kTraceError);
384 return -1;
385 }
386
387 {
388 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
389 voe::Channel* channelPtr = ch.channel();
390 if (channelPtr == nullptr) {
391 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
392 "DeleteChannel() failed to locate channel");
393 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000394 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200395 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000396
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200397 shared_->channel_manager().DestroyChannel(channel);
398 if (StopSend() != 0) {
399 return -1;
400 }
401 if (StopPlayout() != 0) {
402 return -1;
403 }
404 return 0;
405}
niklase@google.com470e71d2011-07-07 08:21:25 +0000406
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200407int VoEBaseImpl::StartPlayout(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800408 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200409 if (!shared_->statistics().Initialized()) {
410 shared_->SetLastError(VE_NOT_INITED, kTraceError);
411 return -1;
412 }
413 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
414 voe::Channel* channelPtr = ch.channel();
415 if (channelPtr == nullptr) {
416 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
417 "StartPlayout() failed to locate channel");
418 return -1;
419 }
420 if (channelPtr->Playing()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000421 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200422 }
423 if (StartPlayout() != 0) {
424 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
425 "StartPlayout() failed to start playout");
426 return -1;
427 }
428 return channelPtr->StartPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000429}
430
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200431int VoEBaseImpl::StopPlayout(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800432 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200433 if (!shared_->statistics().Initialized()) {
434 shared_->SetLastError(VE_NOT_INITED, kTraceError);
435 return -1;
436 }
437 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
438 voe::Channel* channelPtr = ch.channel();
439 if (channelPtr == nullptr) {
440 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
441 "StopPlayout() failed to locate channel");
442 return -1;
443 }
444 if (channelPtr->StopPlayout() != 0) {
445 LOG_F(LS_WARNING) << "StopPlayout() failed to stop playout for channel "
446 << channel;
447 }
448 return StopPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000449}
450
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200451int VoEBaseImpl::StartSend(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800452 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200453 if (!shared_->statistics().Initialized()) {
454 shared_->SetLastError(VE_NOT_INITED, kTraceError);
455 return -1;
456 }
457 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
458 voe::Channel* channelPtr = ch.channel();
459 if (channelPtr == nullptr) {
460 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
461 "StartSend() failed to locate channel");
462 return -1;
463 }
464 if (channelPtr->Sending()) {
465 return 0;
466 }
467 if (StartSend() != 0) {
468 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
469 "StartSend() failed to start recording");
470 return -1;
471 }
472 return channelPtr->StartSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000473}
474
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200475int VoEBaseImpl::StopSend(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800476 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200477 if (!shared_->statistics().Initialized()) {
478 shared_->SetLastError(VE_NOT_INITED, kTraceError);
479 return -1;
480 }
481 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
482 voe::Channel* channelPtr = ch.channel();
483 if (channelPtr == nullptr) {
484 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
485 "StopSend() failed to locate channel");
486 return -1;
487 }
henrikaec6fbd22017-03-31 05:43:36 -0700488 channelPtr->StopSend();
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200489 return StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000490}
491
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200492int32_t VoEBaseImpl::StartPlayout() {
solenberge313e022015-09-08 02:16:04 -0700493 if (!shared_->audio_device()->Playing()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200494 if (shared_->audio_device()->InitPlayout() != 0) {
495 LOG_F(LS_ERROR) << "Failed to initialize playout";
496 return -1;
497 }
498 if (shared_->audio_device()->StartPlayout() != 0) {
499 LOG_F(LS_ERROR) << "Failed to start playout";
500 return -1;
501 }
502 }
503 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000504}
505
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000506int32_t VoEBaseImpl::StopPlayout() {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000507 // Stop audio-device playing if no channel is playing out
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200508 if (shared_->NumOfPlayingChannels() == 0) {
509 if (shared_->audio_device()->StopPlayout() != 0) {
510 shared_->SetLastError(VE_CANNOT_STOP_PLAYOUT, kTraceError,
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000511 "StopPlayout() failed to stop playout");
512 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000513 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000514 }
515 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000516}
517
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200518int32_t VoEBaseImpl::StartSend() {
solenbergd53a3f92016-04-14 13:56:37 -0700519 if (!shared_->audio_device()->RecordingIsInitialized() &&
520 !shared_->audio_device()->Recording()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200521 if (shared_->audio_device()->InitRecording() != 0) {
522 LOG_F(LS_ERROR) << "Failed to initialize recording";
523 return -1;
524 }
solenbergd53a3f92016-04-14 13:56:37 -0700525 }
526 if (!shared_->audio_device()->Recording()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200527 if (shared_->audio_device()->StartRecording() != 0) {
528 LOG_F(LS_ERROR) << "Failed to start recording";
529 return -1;
530 }
531 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200532 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000533}
534
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200535int32_t VoEBaseImpl::StopSend() {
solenbergb63310a2017-09-18 03:04:12 -0700536 if (shared_->NumOfSendingChannels() == 0) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200537 // Stop audio-device recording if no channel is recording
538 if (shared_->audio_device()->StopRecording() != 0) {
539 shared_->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
540 "StopSend() failed to stop recording");
541 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000542 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200543 shared_->transmit_mixer()->StopSend();
544 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000545
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200546 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000547}
548
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200549int32_t VoEBaseImpl::TerminateInternal() {
550 // Delete any remaining channel objects
551 shared_->channel_manager().DestroyAllChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000552
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200553 if (shared_->process_thread()) {
554 if (shared_->audio_device()) {
555 shared_->process_thread()->DeRegisterModule(shared_->audio_device());
niklase@google.com470e71d2011-07-07 08:21:25 +0000556 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200557 shared_->process_thread()->Stop();
558 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000559
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200560 if (shared_->audio_device()) {
561 if (shared_->audio_device()->StopPlayout() != 0) {
562 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
563 "TerminateInternal() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000564 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200565 if (shared_->audio_device()->StopRecording() != 0) {
566 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
567 "TerminateInternal() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000568 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200569 if (shared_->audio_device()->RegisterEventObserver(nullptr) != 0) {
570 shared_->SetLastError(
571 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
572 "TerminateInternal() failed to de-register event observer "
573 "for the ADM");
574 }
575 if (shared_->audio_device()->RegisterAudioCallback(nullptr) != 0) {
576 shared_->SetLastError(
577 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
578 "TerminateInternal() failed to de-register audio callback "
579 "for the ADM");
580 }
581 if (shared_->audio_device()->Terminate() != 0) {
582 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
583 "TerminateInternal() failed to terminate the ADM");
584 }
585 shared_->set_audio_device(nullptr);
586 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000587
peaha9cc40b2017-06-29 08:32:09 -0700588 shared_->set_audio_processing(nullptr);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200589
590 return shared_->statistics().SetUnInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000591}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000592} // namespace webrtc