Line data Source code
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/audio/utility/audio_frame_operations.h"
14 : #include "webrtc/system_wrappers/include/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 :
21 : namespace webrtc {
22 :
23 0 : VoEExternalMedia* VoEExternalMedia::GetInterface(VoiceEngine* voiceEngine) {
24 0 : if (NULL == voiceEngine) {
25 0 : return NULL;
26 : }
27 0 : VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
28 0 : s->AddRef();
29 0 : return s;
30 : }
31 :
32 0 : VoEExternalMediaImpl::VoEExternalMediaImpl(voe::SharedData* shared)
33 : :
34 : #ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
35 : playout_delay_ms_(0),
36 : #endif
37 0 : shared_(shared) {
38 : WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(shared_->instance_id(), -1),
39 : "VoEExternalMediaImpl() - ctor");
40 0 : }
41 :
42 0 : VoEExternalMediaImpl::~VoEExternalMediaImpl() {
43 : WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(shared_->instance_id(), -1),
44 : "~VoEExternalMediaImpl() - dtor");
45 0 : }
46 :
47 0 : int VoEExternalMediaImpl::RegisterExternalMediaProcessing(
48 : int channel,
49 : ProcessingTypes type,
50 : VoEMediaProcess& processObject) {
51 : WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(shared_->instance_id(), -1),
52 : "RegisterExternalMediaProcessing(channel=%d, type=%d, "
53 : "processObject=0x%x)",
54 : channel, type, &processObject);
55 0 : if (!shared_->statistics().Initialized()) {
56 0 : shared_->SetLastError(VE_NOT_INITED, kTraceError);
57 0 : return -1;
58 : }
59 0 : switch (type) {
60 : case kPlaybackPerChannel:
61 : case kRecordingPerChannel: {
62 0 : voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
63 0 : voe::Channel* channelPtr = ch.channel();
64 0 : if (channelPtr == NULL) {
65 0 : shared_->SetLastError(
66 : VE_CHANNEL_NOT_VALID, kTraceError,
67 : "RegisterExternalMediaProcessing() failed to locate "
68 0 : "channel");
69 0 : return -1;
70 : }
71 0 : return channelPtr->RegisterExternalMediaProcessing(type, processObject);
72 : }
73 : case kPlaybackAllChannelsMixed: {
74 0 : return shared_->output_mixer()->RegisterExternalMediaProcessing(
75 0 : processObject);
76 : }
77 : case kRecordingAllChannelsMixed:
78 : case kRecordingPreprocessing: {
79 0 : return shared_->transmit_mixer()->RegisterExternalMediaProcessing(
80 0 : &processObject, type);
81 : }
82 : }
83 0 : return -1;
84 : }
85 :
86 0 : int VoEExternalMediaImpl::DeRegisterExternalMediaProcessing(
87 : int channel,
88 : ProcessingTypes type) {
89 : WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(shared_->instance_id(), -1),
90 : "DeRegisterExternalMediaProcessing(channel=%d)", channel);
91 0 : if (!shared_->statistics().Initialized()) {
92 0 : shared_->SetLastError(VE_NOT_INITED, kTraceError);
93 0 : return -1;
94 : }
95 0 : switch (type) {
96 : case kPlaybackPerChannel:
97 : case kRecordingPerChannel: {
98 0 : voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
99 0 : voe::Channel* channelPtr = ch.channel();
100 0 : if (channelPtr == NULL) {
101 0 : shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
102 : "RegisterExternalMediaProcessing() "
103 0 : "failed to locate channel");
104 0 : return -1;
105 : }
106 0 : return channelPtr->DeRegisterExternalMediaProcessing(type);
107 : }
108 : case kPlaybackAllChannelsMixed: {
109 0 : return shared_->output_mixer()->DeRegisterExternalMediaProcessing();
110 : }
111 : case kRecordingAllChannelsMixed:
112 : case kRecordingPreprocessing: {
113 0 : return shared_->transmit_mixer()->DeRegisterExternalMediaProcessing(type);
114 : }
115 : }
116 0 : return -1;
117 : }
118 :
119 0 : int VoEExternalMediaImpl::SetExternalRecordingStatus(bool enable)
120 : {
121 : WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(shared_->instance_id(), -1),
122 : "SetExternalRecordingStatus(enable=%d)", enable);
123 : #ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
124 0 : if (shared_->audio_device() && shared_->audio_device()->Recording())
125 : {
126 0 : shared_->SetLastError(VE_ALREADY_SENDING, kTraceError,
127 0 : "SetExternalRecordingStatus() cannot set state while sending");
128 0 : return -1;
129 : }
130 0 : shared_->set_ext_recording(enable);
131 0 : return 0;
132 : #else
133 : shared_->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
134 : "SetExternalRecordingStatus() external recording is not supported");
135 : return -1;
136 : #endif
137 : }
138 :
139 0 : int VoEExternalMediaImpl::ExternalRecordingInsertData(
140 : const int16_t speechData10ms[],
141 : int lengthSamples,
142 : int samplingFreqHz,
143 : int current_delay_ms)
144 : {
145 : WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(shared_->instance_id(), -1),
146 : "ExternalRecordingInsertData(speechData10ms=0x%x,"
147 : " lengthSamples=%u, samplingFreqHz=%d, current_delay_ms=%d)",
148 : &speechData10ms[0], lengthSamples, samplingFreqHz,
149 : current_delay_ms);
150 : #ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
151 0 : if (!shared_->statistics().Initialized())
152 : {
153 0 : shared_->SetLastError(VE_NOT_INITED, kTraceError);
154 0 : return -1;
155 : }
156 0 : if (!shared_->ext_recording())
157 : {
158 0 : shared_->SetLastError(VE_INVALID_OPERATION, kTraceError,
159 0 : "ExternalRecordingInsertData() external recording is not enabled");
160 0 : return -1;
161 : }
162 0 : if (shared_->NumOfSendingChannels() == 0)
163 : {
164 0 : shared_->SetLastError(VE_ALREADY_SENDING, kTraceError,
165 0 : "SetExternalRecordingStatus() no channel is sending");
166 0 : return -1;
167 : }
168 0 : if ((16000 != samplingFreqHz) && (32000 != samplingFreqHz) &&
169 0 : (48000 != samplingFreqHz) && (44100 != samplingFreqHz))
170 : {
171 0 : shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
172 0 : "SetExternalRecordingStatus() invalid sample rate");
173 0 : return -1;
174 : }
175 0 : if ((0 == lengthSamples) ||
176 0 : ((lengthSamples % (samplingFreqHz / 100)) != 0))
177 : {
178 0 : shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
179 0 : "SetExternalRecordingStatus() invalid buffer size");
180 0 : return -1;
181 : }
182 0 : if (current_delay_ms < 0)
183 : {
184 0 : shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
185 0 : "SetExternalRecordingStatus() invalid delay)");
186 0 : return -1;
187 : }
188 :
189 0 : uint16_t blockSize = samplingFreqHz / 100;
190 : // We know the number of samples for 10ms of audio, so we can derive the
191 : // number of channels here:
192 0 : uint32_t channels = lengthSamples * 100 / samplingFreqHz;
193 0 : uint32_t nBlocks = lengthSamples / blockSize / channels;
194 0 : int16_t totalDelayMS = 0;
195 0 : uint16_t playoutDelayMS = 0;
196 :
197 0 : for (uint32_t i = 0; i < nBlocks; i++)
198 : {
199 0 : if (!shared_->ext_playout())
200 : {
201 : // Use real playout delay if external playout is not enabled.
202 0 : if (shared_->audio_device()->PlayoutDelay(&playoutDelayMS) != 0) {
203 0 : shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
204 0 : "PlayoutDelay() unable to get the playout delay");
205 : }
206 0 : totalDelayMS = current_delay_ms + playoutDelayMS;
207 : }
208 : else
209 : {
210 : // Use stored delay value given the last call
211 : // to ExternalPlayoutGetData.
212 0 : totalDelayMS = current_delay_ms + playout_delay_ms_;
213 : // Compensate for block sizes larger than 10ms
214 0 : totalDelayMS -= (int16_t)(i*10);
215 0 : if (totalDelayMS < 0)
216 0 : totalDelayMS = 0;
217 : }
218 0 : shared_->transmit_mixer()->PrepareDemux(
219 0 : (const int8_t*)(&speechData10ms[i*blockSize]),
220 : blockSize,
221 : channels,
222 : samplingFreqHz,
223 : totalDelayMS,
224 : 0,
225 : 0,
226 0 : false); // Typing detection not supported
227 :
228 0 : shared_->transmit_mixer()->DemuxAndMix();
229 0 : shared_->transmit_mixer()->EncodeAndSend();
230 : }
231 0 : return 0;
232 : #else
233 : shared_->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
234 : "ExternalRecordingInsertData() external recording is not supported");
235 : return -1;
236 : #endif
237 : }
238 :
239 0 : int VoEExternalMediaImpl::SetExternalPlayoutStatus(bool enable)
240 : {
241 : WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(shared_->instance_id(), -1),
242 : "SetExternalPlayoutStatus(enable=%d)", enable);
243 : #ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
244 0 : if (shared_->audio_device() && shared_->audio_device()->Playing())
245 : {
246 0 : shared_->SetLastError(VE_ALREADY_SENDING, kTraceError,
247 0 : "SetExternalPlayoutStatus() cannot set state while playing");
248 0 : return -1;
249 : }
250 0 : shared_->set_ext_playout(enable);
251 0 : return 0;
252 : #else
253 : shared_->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
254 : "SetExternalPlayoutStatus() external playout is not supported");
255 : return -1;
256 : #endif
257 : }
258 :
259 : // This inserts a copy of the raw audio sent to the output drivers to use
260 : // as the "far end" signal for the AEC. Currently only 10ms chunks are
261 : // supported unfortunately. Since we have to rechunk to 10ms to call this,
262 : // thre isn't much gained by allowing N*10ms here; external code can loop
263 : // if needed.
264 0 : int VoEExternalMediaImpl::ExternalPlayoutData(
265 : int16_t speechData10ms[],
266 : int samplingFreqHz,
267 : int num_channels,
268 : int current_delay_ms,
269 : int& lengthSamples)
270 : {
271 : WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(shared_->instance_id(), -1),
272 : "ExternalPlayoutData(speechData10ms=0x%x,"
273 : " lengthSamples=%u, samplingFreqHz=%d, current_delay_ms=%d)",
274 : &speechData10ms[0], lengthSamples, samplingFreqHz,
275 : current_delay_ms);
276 :
277 : #ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
278 0 : if (!shared_->statistics().Initialized())
279 : {
280 0 : shared_->SetLastError(VE_NOT_INITED, kTraceError);
281 0 : return -1;
282 : }
283 : // FIX(jesup) - check if this is enabled?
284 0 : if (shared_->NumOfSendingChannels() == 0)
285 : {
286 0 : shared_->SetLastError(VE_ALREADY_SENDING, kTraceError,
287 0 : "SetExternalRecordingStatus() no channel is sending");
288 0 : return -1;
289 : }
290 0 : if ((16000 != samplingFreqHz) && (32000 != samplingFreqHz) &&
291 0 : (48000 != samplingFreqHz) && (44100 != samplingFreqHz))
292 : {
293 0 : shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
294 0 : "SetExternalRecordingStatus() invalid sample rate");
295 0 : return -1;
296 : }
297 0 : if (current_delay_ms < 0)
298 : {
299 0 : shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
300 0 : "SetExternalRecordingStatus() invalid delay)");
301 0 : return -1;
302 : }
303 :
304 : // Far-end data is inserted without going through neteq/etc.
305 : // Only supports 10ms chunks; AnalyzeReverseStream() enforces that
306 : // lower down.
307 0 : AudioFrame audioFrame;
308 0 : audioFrame.UpdateFrame(-1, 0xFFFFFFFF,
309 : speechData10ms,
310 0 : lengthSamples,
311 : samplingFreqHz,
312 : AudioFrame::kNormalSpeech,
313 : AudioFrame::kVadUnknown,
314 0 : num_channels);
315 :
316 0 : shared_->output_mixer()->APMAnalyzeReverseStream(audioFrame);
317 : #endif
318 0 : return 0;
319 : }
320 :
321 0 : int VoEExternalMediaImpl::ExternalPlayoutGetData(
322 : int16_t speechData10ms[],
323 : int samplingFreqHz,
324 : int current_delay_ms,
325 : int& lengthSamples)
326 : {
327 : WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(shared_->instance_id(), -1),
328 : "ExternalPlayoutGetData(speechData10ms=0x%x, samplingFreqHz=%d"
329 : ", current_delay_ms=%d)", &speechData10ms[0], samplingFreqHz,
330 : current_delay_ms);
331 : #ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
332 0 : if (!shared_->statistics().Initialized())
333 : {
334 0 : shared_->SetLastError(VE_NOT_INITED, kTraceError);
335 0 : return -1;
336 : }
337 0 : if (!shared_->ext_playout())
338 : {
339 0 : shared_->SetLastError(VE_INVALID_OPERATION, kTraceError,
340 0 : "ExternalPlayoutGetData() external playout is not enabled");
341 0 : return -1;
342 : }
343 0 : if ((16000 != samplingFreqHz) && (32000 != samplingFreqHz) &&
344 0 : (48000 != samplingFreqHz) && (44100 != samplingFreqHz))
345 : {
346 0 : shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
347 0 : "ExternalPlayoutGetData() invalid sample rate");
348 0 : return -1;
349 : }
350 0 : if (current_delay_ms < 0)
351 : {
352 0 : shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
353 0 : "ExternalPlayoutGetData() invalid delay)");
354 0 : return -1;
355 : }
356 :
357 0 : AudioFrame audioFrame;
358 :
359 0 : uint32_t channels = shared_->output_mixer()->GetOutputChannelCount();
360 : // If we have not received any data yet, consider it's mono since it's the
361 : // most common case.
362 0 : if (channels == 0) {
363 0 : channels = 1;
364 : }
365 :
366 : // Retrieve mixed output at the specified rate
367 0 : shared_->output_mixer()->MixActiveChannels();
368 0 : shared_->output_mixer()->DoOperationsOnCombinedSignal(true);
369 0 : shared_->output_mixer()->GetMixedAudio(samplingFreqHz, channels, &audioFrame);
370 :
371 : // Deliver audio (PCM) samples to the external sink
372 0 : memcpy(speechData10ms,
373 : audioFrame.data_,
374 0 : sizeof(int16_t)*audioFrame.samples_per_channel_*channels);
375 0 : lengthSamples = audioFrame.samples_per_channel_ * channels;
376 :
377 : // Store current playout delay (to be used by ExternalRecordingInsertData).
378 0 : playout_delay_ms_ = current_delay_ms;
379 :
380 0 : return 0;
381 : #else
382 : shared_->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
383 : "ExternalPlayoutGetData() external playout is not supported");
384 : return -1;
385 : #endif
386 : }
387 :
388 0 : int VoEExternalMediaImpl::GetAudioFrame(int channel, int desired_sample_rate_hz,
389 : AudioFrame* frame) {
390 0 : if (!shared_->statistics().Initialized()) {
391 0 : shared_->SetLastError(VE_NOT_INITED, kTraceError);
392 0 : return -1;
393 : }
394 0 : voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
395 0 : voe::Channel* channelPtr = ch.channel();
396 0 : if (channelPtr == NULL) {
397 0 : shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
398 0 : "GetAudioFrame() failed to locate channel");
399 0 : return -1;
400 : }
401 0 : if (!channelPtr->ExternalMixing()) {
402 0 : shared_->SetLastError(VE_INVALID_OPERATION, kTraceError,
403 : "GetAudioFrame() was called on channel that is not"
404 0 : " externally mixed.");
405 0 : return -1;
406 : }
407 0 : if (!channelPtr->Playing()) {
408 0 : shared_->SetLastError(
409 : VE_INVALID_OPERATION, kTraceError,
410 0 : "GetAudioFrame() was called on channel that is not playing.");
411 0 : return -1;
412 : }
413 0 : if (desired_sample_rate_hz == -1) {
414 0 : shared_->SetLastError(VE_BAD_ARGUMENT, kTraceError,
415 0 : "GetAudioFrame() was called with bad sample rate.");
416 0 : return -1;
417 : }
418 0 : frame->sample_rate_hz_ =
419 0 : desired_sample_rate_hz == 0 ? -1 : desired_sample_rate_hz;
420 0 : auto ret = channelPtr->GetAudioFrameWithMuted(channel, frame);
421 0 : if (ret == MixerParticipant::AudioFrameInfo::kMuted) {
422 0 : AudioFrameOperations::Mute(frame);
423 : }
424 0 : return ret == MixerParticipant::AudioFrameInfo::kError ? -1 : 0;
425 : }
426 :
427 0 : int VoEExternalMediaImpl::SetExternalMixing(int channel, bool enable) {
428 : WEBRTC_TRACE(kTraceApiCall, kTraceVoice,
429 : VoEId(shared_->instance_id(), channel),
430 : "SetExternalMixing(channel=%d, enable=%d)", channel, enable);
431 0 : if (!shared_->statistics().Initialized()) {
432 0 : shared_->SetLastError(VE_NOT_INITED, kTraceError);
433 0 : return -1;
434 : }
435 0 : voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
436 0 : voe::Channel* channelPtr = ch.channel();
437 0 : if (channelPtr == NULL) {
438 0 : shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
439 0 : "SetExternalMixing() failed to locate channel");
440 0 : return -1;
441 : }
442 0 : return channelPtr->SetExternalMixing(enable);
443 : }
444 :
445 : } // namespace webrtc
|