voe_external_media_impl.cc revision 3f9db3735ee760803fbd687189743b22747f6e54
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 "voe_external_media_impl.h" 12 13#include "channel.h" 14#include "critical_section_wrapper.h" 15#include "output_mixer.h" 16#include "trace.h" 17#include "transmit_mixer.h" 18#include "voice_engine_impl.h" 19#include "voe_errors.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 = reinterpret_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 ANDROID_NOT_SUPPORTED(shared_->statistics()); 66 IPHONE_NOT_SUPPORTED(shared_->statistics()); 67 if (!shared_->statistics().Initialized()) 68 { 69 shared_->SetLastError(VE_NOT_INITED, kTraceError); 70 return -1; 71 } 72 switch (type) 73 { 74 case kPlaybackPerChannel: 75 case kRecordingPerChannel: 76 { 77 voe::ScopedChannel sc(shared_->channel_manager(), channel); 78 voe::Channel* channelPtr = sc.ChannelPtr(); 79 if (channelPtr == NULL) 80 { 81 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 82 "RegisterExternalMediaProcessing() failed to locate " 83 "channel"); 84 return -1; 85 } 86 return channelPtr->RegisterExternalMediaProcessing(type, 87 processObject); 88 } 89 case kPlaybackAllChannelsMixed: 90 { 91 return shared_->output_mixer()->RegisterExternalMediaProcessing( 92 processObject); 93 } 94 case kRecordingAllChannelsMixed: 95 case kRecordingPreprocessing: 96 { 97 return shared_->transmit_mixer()->RegisterExternalMediaProcessing( 98 &processObject, type); 99 } 100 } 101 return -1; 102} 103 104int VoEExternalMediaImpl::DeRegisterExternalMediaProcessing( 105 int channel, 106 ProcessingTypes type) 107{ 108 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(shared_->instance_id(), -1), 109 "DeRegisterExternalMediaProcessing(channel=%d)", channel); 110 ANDROID_NOT_SUPPORTED(shared_->statistics()); 111 IPHONE_NOT_SUPPORTED(shared_->statistics()); 112 if (!shared_->statistics().Initialized()) 113 { 114 shared_->SetLastError(VE_NOT_INITED, kTraceError); 115 return -1; 116 } 117 switch (type) 118 { 119 case kPlaybackPerChannel: 120 case kRecordingPerChannel: 121 { 122 voe::ScopedChannel sc(shared_->channel_manager(), channel); 123 voe::Channel* channelPtr = sc.ChannelPtr(); 124 if (channelPtr == NULL) 125 { 126 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 127 "RegisterExternalMediaProcessing() " 128 "failed to locate channel"); 129 return -1; 130 } 131 return channelPtr->DeRegisterExternalMediaProcessing(type); 132 } 133 case kPlaybackAllChannelsMixed: 134 { 135 return shared_->output_mixer()-> 136 DeRegisterExternalMediaProcessing(); 137 } 138 case kRecordingAllChannelsMixed: 139 case kRecordingPreprocessing: 140 { 141 return shared_->transmit_mixer()-> 142 DeRegisterExternalMediaProcessing(type); 143 } 144 } 145 return -1; 146} 147 148int VoEExternalMediaImpl::SetExternalRecordingStatus(bool enable) 149{ 150 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(shared_->instance_id(), -1), 151 "SetExternalRecordingStatus(enable=%d)", enable); 152 ANDROID_NOT_SUPPORTED(shared_->statistics()); 153 IPHONE_NOT_SUPPORTED(shared_->statistics()); 154#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT 155 if (shared_->audio_device()->Recording()) 156 { 157 shared_->SetLastError(VE_ALREADY_SENDING, kTraceError, 158 "SetExternalRecordingStatus() cannot set state while sending"); 159 return -1; 160 } 161 shared_->set_ext_recording(enable); 162 return 0; 163#else 164 shared_->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 165 "SetExternalRecordingStatus() external recording is not supported"); 166 return -1; 167#endif 168} 169 170int VoEExternalMediaImpl::ExternalRecordingInsertData( 171 const WebRtc_Word16 speechData10ms[], 172 int lengthSamples, 173 int samplingFreqHz, 174 int current_delay_ms) 175{ 176 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(shared_->instance_id(), -1), 177 "ExternalRecordingInsertData(speechData10ms=0x%x," 178 " lengthSamples=%u, samplingFreqHz=%d, current_delay_ms=%d)", 179 &speechData10ms[0], lengthSamples, samplingFreqHz, 180 current_delay_ms); 181 ANDROID_NOT_SUPPORTED(shared_->statistics()); 182 IPHONE_NOT_SUPPORTED(shared_->statistics()); 183 184#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT 185 if (!shared_->statistics().Initialized()) 186 { 187 shared_->SetLastError(VE_NOT_INITED, kTraceError); 188 return -1; 189 } 190 if (!shared_->ext_recording()) 191 { 192 shared_->SetLastError(VE_INVALID_OPERATION, kTraceError, 193 "ExternalRecordingInsertData() external recording is not enabled"); 194 return -1; 195 } 196 if (shared_->NumOfSendingChannels() == 0) 197 { 198 shared_->SetLastError(VE_ALREADY_SENDING, kTraceError, 199 "SetExternalRecordingStatus() no channel is sending"); 200 return -1; 201 } 202 if ((16000 != samplingFreqHz) && (32000 != samplingFreqHz) && 203 (48000 != samplingFreqHz) && (44000 != samplingFreqHz)) 204 { 205 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError, 206 "SetExternalRecordingStatus() invalid sample rate"); 207 return -1; 208 } 209 if ((0 == lengthSamples) || 210 ((lengthSamples % (samplingFreqHz / 100)) != 0)) 211 { 212 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError, 213 "SetExternalRecordingStatus() invalid buffer size"); 214 return -1; 215 } 216 if (current_delay_ms < 0) 217 { 218 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError, 219 "SetExternalRecordingStatus() invalid delay)"); 220 return -1; 221 } 222 223 WebRtc_UWord16 blockSize = samplingFreqHz / 100; 224 WebRtc_UWord32 nBlocks = lengthSamples / blockSize; 225 WebRtc_Word16 totalDelayMS = 0; 226 WebRtc_UWord16 playoutDelayMS = 0; 227 228 for (WebRtc_UWord32 i = 0; i < nBlocks; i++) 229 { 230 if (!shared_->ext_playout()) 231 { 232 // Use real playout delay if external playout is not enabled. 233 if (shared_->audio_device()->PlayoutDelay(&playoutDelayMS) != 0) { 234 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning, 235 "PlayoutDelay() unable to get the playout delay"); 236 } 237 totalDelayMS = current_delay_ms + playoutDelayMS; 238 } 239 else 240 { 241 // Use stored delay value given the last call 242 // to ExternalPlayoutGetData. 243 totalDelayMS = current_delay_ms + playout_delay_ms_; 244 // Compensate for block sizes larger than 10ms 245 totalDelayMS -= (WebRtc_Word16)(i*10); 246 if (totalDelayMS < 0) 247 totalDelayMS = 0; 248 } 249 shared_->transmit_mixer()->PrepareDemux( 250 (const WebRtc_Word8*)(&speechData10ms[i*blockSize]), 251 blockSize, 252 1, 253 samplingFreqHz, 254 totalDelayMS, 255 0, 256 0); 257 258 shared_->transmit_mixer()->DemuxAndMix(); 259 shared_->transmit_mixer()->EncodeAndSend(); 260 } 261 return 0; 262#else 263 shared_->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 264 "ExternalRecordingInsertData() external recording is not supported"); 265 return -1; 266#endif 267} 268 269int VoEExternalMediaImpl::SetExternalPlayoutStatus(bool enable) 270{ 271 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(shared_->instance_id(), -1), 272 "SetExternalPlayoutStatus(enable=%d)", enable); 273 ANDROID_NOT_SUPPORTED(shared_->statistics()); 274 IPHONE_NOT_SUPPORTED(shared_->statistics()); 275#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT 276 if (shared_->audio_device()->Playing()) 277 { 278 shared_->SetLastError(VE_ALREADY_SENDING, kTraceError, 279 "SetExternalPlayoutStatus() cannot set state while playing"); 280 return -1; 281 } 282 shared_->set_ext_playout(enable); 283 return 0; 284#else 285 shared_->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 286 "SetExternalPlayoutStatus() external playout is not supported"); 287 return -1; 288#endif 289} 290 291int VoEExternalMediaImpl::ExternalPlayoutGetData( 292 WebRtc_Word16 speechData10ms[], 293 int samplingFreqHz, 294 int current_delay_ms, 295 int& lengthSamples) 296{ 297 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(shared_->instance_id(), -1), 298 "ExternalPlayoutGetData(speechData10ms=0x%x, samplingFreqHz=%d" 299 ", current_delay_ms=%d)", &speechData10ms[0], samplingFreqHz, 300 current_delay_ms); 301 ANDROID_NOT_SUPPORTED(shared_->statistics()); 302 IPHONE_NOT_SUPPORTED(shared_->statistics()); 303#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT 304 if (!shared_->statistics().Initialized()) 305 { 306 shared_->SetLastError(VE_NOT_INITED, kTraceError); 307 return -1; 308 } 309 if (!shared_->ext_playout()) 310 { 311 shared_->SetLastError(VE_INVALID_OPERATION, kTraceError, 312 "ExternalPlayoutGetData() external playout is not enabled"); 313 return -1; 314 } 315 if ((16000 != samplingFreqHz) && (32000 != samplingFreqHz) && 316 (48000 != samplingFreqHz) && (44000 != samplingFreqHz)) 317 { 318 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError, 319 "ExternalPlayoutGetData() invalid sample rate"); 320 return -1; 321 } 322 if (current_delay_ms < 0) 323 { 324 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError, 325 "ExternalPlayoutGetData() invalid delay)"); 326 return -1; 327 } 328 329 AudioFrame audioFrame; 330 331 // Retrieve mixed output at the specified rate 332 shared_->output_mixer()->MixActiveChannels(); 333 shared_->output_mixer()->DoOperationsOnCombinedSignal(); 334 shared_->output_mixer()->GetMixedAudio(samplingFreqHz, 1, &audioFrame); 335 336 // Deliver audio (PCM) samples to the external sink 337 memcpy(speechData10ms, 338 audioFrame.data_, 339 sizeof(WebRtc_Word16)*(audioFrame.samples_per_channel_)); 340 lengthSamples = audioFrame.samples_per_channel_; 341 342 // Store current playout delay (to be used by ExternalRecordingInsertData). 343 playout_delay_ms_ = current_delay_ms; 344 345 return 0; 346#else 347 shared_->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 348 "ExternalPlayoutGetData() external playout is not supported"); 349 return -1; 350#endif 351} 352 353int VoEExternalMediaImpl::GetAudioFrame(int channel, int desired_sample_rate_hz, 354 AudioFrame* frame) { 355 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, 356 VoEId(shared_->instance_id(), channel), 357 "GetAudioFrame(channel=%d, desired_sample_rate_hz=%d)", 358 channel, desired_sample_rate_hz); 359 if (!shared_->statistics().Initialized()) 360 { 361 shared_->SetLastError(VE_NOT_INITED, kTraceError); 362 return -1; 363 } 364 voe::ScopedChannel sc(shared_->channel_manager(), channel); 365 voe::Channel* channelPtr = sc.ChannelPtr(); 366 if (channelPtr == NULL) 367 { 368 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 369 "GetAudioFrame() failed to locate channel"); 370 return -1; 371 } 372 if (!channelPtr->ExternalMixing()) { 373 shared_->SetLastError(VE_INVALID_OPERATION, kTraceError, 374 "GetAudioFrame() was called on channel that is not" 375 " externally mixed."); 376 return -1; 377 } 378 if (!channelPtr->Playing()) { 379 shared_->SetLastError(VE_INVALID_OPERATION, kTraceError, 380 "GetAudioFrame() was called on channel that is not playing."); 381 return -1; 382 } 383 if (desired_sample_rate_hz == -1) { 384 shared_->SetLastError(VE_BAD_ARGUMENT, kTraceError, 385 "GetAudioFrame() was called with bad sample rate."); 386 return -1; 387 } 388 frame->sample_rate_hz_ = desired_sample_rate_hz == 0 ? -1 : 389 desired_sample_rate_hz; 390 return channelPtr->GetAudioFrame(channel, *frame); 391} 392 393int VoEExternalMediaImpl::SetExternalMixing(int channel, bool enable) { 394 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, 395 VoEId(shared_->instance_id(), channel), 396 "SetExternalMixing(channel=%d, enable=%d)", channel, enable); 397 if (!shared_->statistics().Initialized()) 398 { 399 shared_->SetLastError(VE_NOT_INITED, kTraceError); 400 return -1; 401 } 402 voe::ScopedChannel sc(shared_->channel_manager(), channel); 403 voe::Channel* channelPtr = sc.ChannelPtr(); 404 if (channelPtr == NULL) 405 { 406 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 407 "SetExternalMixing() failed to locate channel"); 408 return -1; 409 } 410 return channelPtr->SetExternalMixing(enable); 411} 412 413#endif // WEBRTC_VOICE_ENGINE_EXTERNAL_MEDIA_API 414 415} // namespace webrtc 416