voe_external_media_impl.cc revision 956aa7e0874f2e08c335a82a2c32f400fac8b031
1/* 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#include "webrtc/voice_engine/voe_external_media_impl.h" 12 13#include "webrtc/system_wrappers/interface/critical_section_wrapper.h" 14#include "webrtc/system_wrappers/interface/trace.h" 15#include "webrtc/voice_engine/channel.h" 16#include "webrtc/voice_engine/include/voe_errors.h" 17#include "webrtc/voice_engine/output_mixer.h" 18#include "webrtc/voice_engine/transmit_mixer.h" 19#include "webrtc/voice_engine/voice_engine_impl.h" 20 21namespace webrtc { 22 23VoEExternalMedia* VoEExternalMedia::GetInterface(VoiceEngine* voiceEngine) 24{ 25#ifndef WEBRTC_VOICE_ENGINE_EXTERNAL_MEDIA_API 26 return NULL; 27#else 28 if (NULL == voiceEngine) 29 { 30 return NULL; 31 } 32 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine); 33 s->AddRef(); 34 return s; 35#endif 36} 37 38#ifdef WEBRTC_VOICE_ENGINE_EXTERNAL_MEDIA_API 39 40VoEExternalMediaImpl::VoEExternalMediaImpl(voe::SharedData* shared) 41 : 42#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT 43 playout_delay_ms_(0), 44#endif 45 shared_(shared) 46{ 47 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(shared_->instance_id(), -1), 48 "VoEExternalMediaImpl() - ctor"); 49} 50 51VoEExternalMediaImpl::~VoEExternalMediaImpl() 52{ 53 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(shared_->instance_id(), -1), 54 "~VoEExternalMediaImpl() - dtor"); 55} 56 57int VoEExternalMediaImpl::RegisterExternalMediaProcessing( 58 int channel, 59 ProcessingTypes type, 60 VoEMediaProcess& processObject) 61{ 62 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(shared_->instance_id(), -1), 63 "RegisterExternalMediaProcessing(channel=%d, type=%d, " 64 "processObject=0x%x)", channel, type, &processObject); 65 if (!shared_->statistics().Initialized()) 66 { 67 shared_->SetLastError(VE_NOT_INITED, kTraceError); 68 return -1; 69 } 70 switch (type) 71 { 72 case kPlaybackPerChannel: 73 case kRecordingPerChannel: 74 { 75 voe::ScopedChannel sc(shared_->channel_manager(), channel); 76 voe::Channel* channelPtr = sc.ChannelPtr(); 77 if (channelPtr == NULL) 78 { 79 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 80 "RegisterExternalMediaProcessing() failed to locate " 81 "channel"); 82 return -1; 83 } 84 return channelPtr->RegisterExternalMediaProcessing(type, 85 processObject); 86 } 87 case kPlaybackAllChannelsMixed: 88 { 89 return shared_->output_mixer()->RegisterExternalMediaProcessing( 90 processObject); 91 } 92 case kRecordingAllChannelsMixed: 93 case kRecordingPreprocessing: 94 { 95 return shared_->transmit_mixer()->RegisterExternalMediaProcessing( 96 &processObject, type); 97 } 98 } 99 return -1; 100} 101 102int VoEExternalMediaImpl::DeRegisterExternalMediaProcessing( 103 int channel, 104 ProcessingTypes type) 105{ 106 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(shared_->instance_id(), -1), 107 "DeRegisterExternalMediaProcessing(channel=%d)", channel); 108 if (!shared_->statistics().Initialized()) 109 { 110 shared_->SetLastError(VE_NOT_INITED, kTraceError); 111 return -1; 112 } 113 switch (type) 114 { 115 case kPlaybackPerChannel: 116 case kRecordingPerChannel: 117 { 118 voe::ScopedChannel sc(shared_->channel_manager(), channel); 119 voe::Channel* channelPtr = sc.ChannelPtr(); 120 if (channelPtr == NULL) 121 { 122 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 123 "RegisterExternalMediaProcessing() " 124 "failed to locate channel"); 125 return -1; 126 } 127 return channelPtr->DeRegisterExternalMediaProcessing(type); 128 } 129 case kPlaybackAllChannelsMixed: 130 { 131 return shared_->output_mixer()-> 132 DeRegisterExternalMediaProcessing(); 133 } 134 case kRecordingAllChannelsMixed: 135 case kRecordingPreprocessing: 136 { 137 return shared_->transmit_mixer()-> 138 DeRegisterExternalMediaProcessing(type); 139 } 140 } 141 return -1; 142} 143 144int VoEExternalMediaImpl::SetExternalRecordingStatus(bool enable) 145{ 146 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(shared_->instance_id(), -1), 147 "SetExternalRecordingStatus(enable=%d)", enable); 148#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT 149 if (shared_->audio_device()->Recording()) 150 { 151 shared_->SetLastError(VE_ALREADY_SENDING, kTraceError, 152 "SetExternalRecordingStatus() cannot set state while sending"); 153 return -1; 154 } 155 shared_->set_ext_recording(enable); 156 return 0; 157#else 158 shared_->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 159 "SetExternalRecordingStatus() external recording is not supported"); 160 return -1; 161#endif 162} 163 164int VoEExternalMediaImpl::ExternalRecordingInsertData( 165 const int16_t speechData10ms[], 166 int lengthSamples, 167 int samplingFreqHz, 168 int current_delay_ms) 169{ 170 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(shared_->instance_id(), -1), 171 "ExternalRecordingInsertData(speechData10ms=0x%x," 172 " lengthSamples=%u, samplingFreqHz=%d, current_delay_ms=%d)", 173 &speechData10ms[0], lengthSamples, samplingFreqHz, 174 current_delay_ms); 175#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT 176 if (!shared_->statistics().Initialized()) 177 { 178 shared_->SetLastError(VE_NOT_INITED, kTraceError); 179 return -1; 180 } 181 if (!shared_->ext_recording()) 182 { 183 shared_->SetLastError(VE_INVALID_OPERATION, kTraceError, 184 "ExternalRecordingInsertData() external recording is not enabled"); 185 return -1; 186 } 187 if (shared_->NumOfSendingChannels() == 0) 188 { 189 shared_->SetLastError(VE_ALREADY_SENDING, kTraceError, 190 "SetExternalRecordingStatus() no channel is sending"); 191 return -1; 192 } 193 if ((16000 != samplingFreqHz) && (32000 != samplingFreqHz) && 194 (48000 != samplingFreqHz) && (44000 != samplingFreqHz)) 195 { 196 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError, 197 "SetExternalRecordingStatus() invalid sample rate"); 198 return -1; 199 } 200 if ((0 == lengthSamples) || 201 ((lengthSamples % (samplingFreqHz / 100)) != 0)) 202 { 203 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError, 204 "SetExternalRecordingStatus() invalid buffer size"); 205 return -1; 206 } 207 if (current_delay_ms < 0) 208 { 209 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError, 210 "SetExternalRecordingStatus() invalid delay)"); 211 return -1; 212 } 213 214 uint16_t blockSize = samplingFreqHz / 100; 215 uint32_t nBlocks = lengthSamples / blockSize; 216 int16_t totalDelayMS = 0; 217 uint16_t playoutDelayMS = 0; 218 219 for (uint32_t i = 0; i < nBlocks; i++) 220 { 221 if (!shared_->ext_playout()) 222 { 223 // Use real playout delay if external playout is not enabled. 224 if (shared_->audio_device()->PlayoutDelay(&playoutDelayMS) != 0) { 225 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning, 226 "PlayoutDelay() unable to get the playout delay"); 227 } 228 totalDelayMS = current_delay_ms + playoutDelayMS; 229 } 230 else 231 { 232 // Use stored delay value given the last call 233 // to ExternalPlayoutGetData. 234 totalDelayMS = current_delay_ms + playout_delay_ms_; 235 // Compensate for block sizes larger than 10ms 236 totalDelayMS -= (int16_t)(i*10); 237 if (totalDelayMS < 0) 238 totalDelayMS = 0; 239 } 240 shared_->transmit_mixer()->PrepareDemux( 241 (const int8_t*)(&speechData10ms[i*blockSize]), 242 blockSize, 243 1, 244 samplingFreqHz, 245 totalDelayMS, 246 0, 247 0, 248 false); // Typing detection not supported 249 250 shared_->transmit_mixer()->DemuxAndMix(); 251 shared_->transmit_mixer()->EncodeAndSend(); 252 } 253 return 0; 254#else 255 shared_->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 256 "ExternalRecordingInsertData() external recording is not supported"); 257 return -1; 258#endif 259} 260 261int VoEExternalMediaImpl::SetExternalPlayoutStatus(bool enable) 262{ 263 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(shared_->instance_id(), -1), 264 "SetExternalPlayoutStatus(enable=%d)", enable); 265#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT 266 if (shared_->audio_device()->Playing()) 267 { 268 shared_->SetLastError(VE_ALREADY_SENDING, kTraceError, 269 "SetExternalPlayoutStatus() cannot set state while playing"); 270 return -1; 271 } 272 shared_->set_ext_playout(enable); 273 return 0; 274#else 275 shared_->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 276 "SetExternalPlayoutStatus() external playout is not supported"); 277 return -1; 278#endif 279} 280 281int VoEExternalMediaImpl::ExternalPlayoutGetData( 282 int16_t speechData10ms[], 283 int samplingFreqHz, 284 int current_delay_ms, 285 int& lengthSamples) 286{ 287 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(shared_->instance_id(), -1), 288 "ExternalPlayoutGetData(speechData10ms=0x%x, samplingFreqHz=%d" 289 ", current_delay_ms=%d)", &speechData10ms[0], samplingFreqHz, 290 current_delay_ms); 291#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT 292 if (!shared_->statistics().Initialized()) 293 { 294 shared_->SetLastError(VE_NOT_INITED, kTraceError); 295 return -1; 296 } 297 if (!shared_->ext_playout()) 298 { 299 shared_->SetLastError(VE_INVALID_OPERATION, kTraceError, 300 "ExternalPlayoutGetData() external playout is not enabled"); 301 return -1; 302 } 303 if ((16000 != samplingFreqHz) && (32000 != samplingFreqHz) && 304 (48000 != samplingFreqHz) && (44000 != samplingFreqHz)) 305 { 306 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError, 307 "ExternalPlayoutGetData() invalid sample rate"); 308 return -1; 309 } 310 if (current_delay_ms < 0) 311 { 312 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError, 313 "ExternalPlayoutGetData() invalid delay)"); 314 return -1; 315 } 316 317 AudioFrame audioFrame; 318 319 // Retrieve mixed output at the specified rate 320 shared_->output_mixer()->MixActiveChannels(); 321 shared_->output_mixer()->DoOperationsOnCombinedSignal(); 322 shared_->output_mixer()->GetMixedAudio(samplingFreqHz, 1, &audioFrame); 323 324 // Deliver audio (PCM) samples to the external sink 325 memcpy(speechData10ms, 326 audioFrame.data_, 327 sizeof(int16_t)*(audioFrame.samples_per_channel_)); 328 lengthSamples = audioFrame.samples_per_channel_; 329 330 // Store current playout delay (to be used by ExternalRecordingInsertData). 331 playout_delay_ms_ = current_delay_ms; 332 333 return 0; 334#else 335 shared_->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 336 "ExternalPlayoutGetData() external playout is not supported"); 337 return -1; 338#endif 339} 340 341int VoEExternalMediaImpl::GetAudioFrame(int channel, int desired_sample_rate_hz, 342 AudioFrame* frame) { 343 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, 344 VoEId(shared_->instance_id(), channel), 345 "GetAudioFrame(channel=%d, desired_sample_rate_hz=%d)", 346 channel, desired_sample_rate_hz); 347 if (!shared_->statistics().Initialized()) 348 { 349 shared_->SetLastError(VE_NOT_INITED, kTraceError); 350 return -1; 351 } 352 voe::ScopedChannel sc(shared_->channel_manager(), channel); 353 voe::Channel* channelPtr = sc.ChannelPtr(); 354 if (channelPtr == NULL) 355 { 356 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 357 "GetAudioFrame() failed to locate channel"); 358 return -1; 359 } 360 if (!channelPtr->ExternalMixing()) { 361 shared_->SetLastError(VE_INVALID_OPERATION, kTraceError, 362 "GetAudioFrame() was called on channel that is not" 363 " externally mixed."); 364 return -1; 365 } 366 if (!channelPtr->Playing()) { 367 shared_->SetLastError(VE_INVALID_OPERATION, kTraceError, 368 "GetAudioFrame() was called on channel that is not playing."); 369 return -1; 370 } 371 if (desired_sample_rate_hz == -1) { 372 shared_->SetLastError(VE_BAD_ARGUMENT, kTraceError, 373 "GetAudioFrame() was called with bad sample rate."); 374 return -1; 375 } 376 frame->sample_rate_hz_ = desired_sample_rate_hz == 0 ? -1 : 377 desired_sample_rate_hz; 378 return channelPtr->GetAudioFrame(channel, *frame); 379} 380 381int VoEExternalMediaImpl::SetExternalMixing(int channel, bool enable) { 382 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, 383 VoEId(shared_->instance_id(), channel), 384 "SetExternalMixing(channel=%d, enable=%d)", channel, enable); 385 if (!shared_->statistics().Initialized()) 386 { 387 shared_->SetLastError(VE_NOT_INITED, kTraceError); 388 return -1; 389 } 390 voe::ScopedChannel sc(shared_->channel_manager(), channel); 391 voe::Channel* channelPtr = sc.ChannelPtr(); 392 if (channelPtr == NULL) 393 { 394 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 395 "SetExternalMixing() failed to locate channel"); 396 return -1; 397 } 398 return channelPtr->SetExternalMixing(enable); 399} 400 401#endif // WEBRTC_VOICE_ENGINE_EXTERNAL_MEDIA_API 402 403} // namespace webrtc 404