blob: 28d7c1a96b0fbf9a815271be8b5db308f9b1b0ef [file] [log] [blame]
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001/*
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
pbos@webrtc.org471ae722013-05-21 13:52:32 +000011#include "webrtc/voice_engine/voe_external_media_impl.h"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000012
pbos@webrtc.org471ae722013-05-21 13:52:32 +000013#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"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000020
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 }
tommi@webrtc.orgb9e5a3d2013-02-15 15:07:32 +000032 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000033 s->AddRef();
34 return s;
35#endif
36}
37
38#ifdef WEBRTC_VOICE_ENGINE_EXTERNAL_MEDIA_API
39
40VoEExternalMediaImpl::VoEExternalMediaImpl(voe::SharedData* shared)
wjia@webrtc.org7b1e78d2013-01-12 01:09:03 +000041 :
42#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
43 playout_delay_ms_(0),
44#endif
45 shared_(shared)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000046{
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);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000065 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 {
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +000075 voe::ChannelOwner ch =
76 shared_->channel_manager().GetChannel(channel);
77 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000078 if (channelPtr == NULL)
79 {
80 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
81 "RegisterExternalMediaProcessing() failed to locate "
82 "channel");
83 return -1;
84 }
85 return channelPtr->RegisterExternalMediaProcessing(type,
86 processObject);
87 }
88 case kPlaybackAllChannelsMixed:
89 {
90 return shared_->output_mixer()->RegisterExternalMediaProcessing(
91 processObject);
92 }
93 case kRecordingAllChannelsMixed:
94 case kRecordingPreprocessing:
95 {
96 return shared_->transmit_mixer()->RegisterExternalMediaProcessing(
97 &processObject, type);
98 }
99 }
100 return -1;
101}
102
103int VoEExternalMediaImpl::DeRegisterExternalMediaProcessing(
104 int channel,
105 ProcessingTypes type)
106{
107 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(shared_->instance_id(), -1),
108 "DeRegisterExternalMediaProcessing(channel=%d)", channel);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000109 if (!shared_->statistics().Initialized())
110 {
111 shared_->SetLastError(VE_NOT_INITED, kTraceError);
112 return -1;
113 }
114 switch (type)
115 {
116 case kPlaybackPerChannel:
117 case kRecordingPerChannel:
118 {
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000119 voe::ChannelOwner ch =
120 shared_->channel_manager().GetChannel(channel);
121 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000122 if (channelPtr == NULL)
123 {
124 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
125 "RegisterExternalMediaProcessing() "
126 "failed to locate channel");
127 return -1;
128 }
129 return channelPtr->DeRegisterExternalMediaProcessing(type);
130 }
131 case kPlaybackAllChannelsMixed:
132 {
133 return shared_->output_mixer()->
134 DeRegisterExternalMediaProcessing();
135 }
136 case kRecordingAllChannelsMixed:
137 case kRecordingPreprocessing:
138 {
139 return shared_->transmit_mixer()->
140 DeRegisterExternalMediaProcessing(type);
141 }
142 }
143 return -1;
144}
145
146int VoEExternalMediaImpl::SetExternalRecordingStatus(bool enable)
147{
148 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(shared_->instance_id(), -1),
149 "SetExternalRecordingStatus(enable=%d)", enable);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000150#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
151 if (shared_->audio_device()->Recording())
152 {
153 shared_->SetLastError(VE_ALREADY_SENDING, kTraceError,
154 "SetExternalRecordingStatus() cannot set state while sending");
155 return -1;
156 }
157 shared_->set_ext_recording(enable);
158 return 0;
159#else
160 shared_->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
161 "SetExternalRecordingStatus() external recording is not supported");
162 return -1;
163#endif
164}
165
166int VoEExternalMediaImpl::ExternalRecordingInsertData(
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000167 const int16_t speechData10ms[],
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000168 int lengthSamples,
169 int samplingFreqHz,
170 int current_delay_ms)
171{
172 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(shared_->instance_id(), -1),
173 "ExternalRecordingInsertData(speechData10ms=0x%x,"
174 " lengthSamples=%u, samplingFreqHz=%d, current_delay_ms=%d)",
175 &speechData10ms[0], lengthSamples, samplingFreqHz,
176 current_delay_ms);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000177#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
178 if (!shared_->statistics().Initialized())
179 {
180 shared_->SetLastError(VE_NOT_INITED, kTraceError);
181 return -1;
182 }
183 if (!shared_->ext_recording())
184 {
185 shared_->SetLastError(VE_INVALID_OPERATION, kTraceError,
186 "ExternalRecordingInsertData() external recording is not enabled");
187 return -1;
188 }
189 if (shared_->NumOfSendingChannels() == 0)
190 {
191 shared_->SetLastError(VE_ALREADY_SENDING, kTraceError,
192 "SetExternalRecordingStatus() no channel is sending");
193 return -1;
194 }
195 if ((16000 != samplingFreqHz) && (32000 != samplingFreqHz) &&
196 (48000 != samplingFreqHz) && (44000 != samplingFreqHz))
197 {
198 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
199 "SetExternalRecordingStatus() invalid sample rate");
200 return -1;
201 }
202 if ((0 == lengthSamples) ||
203 ((lengthSamples % (samplingFreqHz / 100)) != 0))
204 {
205 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
206 "SetExternalRecordingStatus() invalid buffer size");
207 return -1;
208 }
209 if (current_delay_ms < 0)
210 {
211 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
212 "SetExternalRecordingStatus() invalid delay)");
213 return -1;
214 }
215
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000216 uint16_t blockSize = samplingFreqHz / 100;
217 uint32_t nBlocks = lengthSamples / blockSize;
218 int16_t totalDelayMS = 0;
219 uint16_t playoutDelayMS = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000220
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000221 for (uint32_t i = 0; i < nBlocks; i++)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000222 {
223 if (!shared_->ext_playout())
224 {
225 // Use real playout delay if external playout is not enabled.
226 if (shared_->audio_device()->PlayoutDelay(&playoutDelayMS) != 0) {
227 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
228 "PlayoutDelay() unable to get the playout delay");
229 }
230 totalDelayMS = current_delay_ms + playoutDelayMS;
231 }
232 else
233 {
234 // Use stored delay value given the last call
235 // to ExternalPlayoutGetData.
236 totalDelayMS = current_delay_ms + playout_delay_ms_;
237 // Compensate for block sizes larger than 10ms
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000238 totalDelayMS -= (int16_t)(i*10);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000239 if (totalDelayMS < 0)
240 totalDelayMS = 0;
241 }
242 shared_->transmit_mixer()->PrepareDemux(
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000243 (const int8_t*)(&speechData10ms[i*blockSize]),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000244 blockSize,
245 1,
246 samplingFreqHz,
247 totalDelayMS,
248 0,
niklas.enbom@webrtc.org28832e12013-05-07 21:04:24 +0000249 0,
250 false); // Typing detection not supported
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000251
252 shared_->transmit_mixer()->DemuxAndMix();
253 shared_->transmit_mixer()->EncodeAndSend();
254 }
255 return 0;
256#else
257 shared_->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
258 "ExternalRecordingInsertData() external recording is not supported");
259 return -1;
260#endif
261}
262
263int VoEExternalMediaImpl::SetExternalPlayoutStatus(bool enable)
264{
265 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(shared_->instance_id(), -1),
266 "SetExternalPlayoutStatus(enable=%d)", enable);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000267#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
268 if (shared_->audio_device()->Playing())
269 {
270 shared_->SetLastError(VE_ALREADY_SENDING, kTraceError,
271 "SetExternalPlayoutStatus() cannot set state while playing");
272 return -1;
273 }
274 shared_->set_ext_playout(enable);
275 return 0;
276#else
277 shared_->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
278 "SetExternalPlayoutStatus() external playout is not supported");
279 return -1;
280#endif
281}
282
283int VoEExternalMediaImpl::ExternalPlayoutGetData(
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000284 int16_t speechData10ms[],
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000285 int samplingFreqHz,
286 int current_delay_ms,
287 int& lengthSamples)
288{
289 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(shared_->instance_id(), -1),
290 "ExternalPlayoutGetData(speechData10ms=0x%x, samplingFreqHz=%d"
291 ", current_delay_ms=%d)", &speechData10ms[0], samplingFreqHz,
292 current_delay_ms);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000293#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
294 if (!shared_->statistics().Initialized())
295 {
296 shared_->SetLastError(VE_NOT_INITED, kTraceError);
297 return -1;
298 }
299 if (!shared_->ext_playout())
300 {
301 shared_->SetLastError(VE_INVALID_OPERATION, kTraceError,
302 "ExternalPlayoutGetData() external playout is not enabled");
303 return -1;
304 }
305 if ((16000 != samplingFreqHz) && (32000 != samplingFreqHz) &&
306 (48000 != samplingFreqHz) && (44000 != samplingFreqHz))
307 {
308 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
309 "ExternalPlayoutGetData() invalid sample rate");
310 return -1;
311 }
312 if (current_delay_ms < 0)
313 {
314 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
315 "ExternalPlayoutGetData() invalid delay)");
316 return -1;
317 }
318
319 AudioFrame audioFrame;
320
321 // Retrieve mixed output at the specified rate
322 shared_->output_mixer()->MixActiveChannels();
xians@webrtc.org91d88e12014-04-14 10:50:37 +0000323 shared_->output_mixer()->DoOperationsOnCombinedSignal(true);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000324 shared_->output_mixer()->GetMixedAudio(samplingFreqHz, 1, &audioFrame);
325
326 // Deliver audio (PCM) samples to the external sink
327 memcpy(speechData10ms,
328 audioFrame.data_,
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000329 sizeof(int16_t)*(audioFrame.samples_per_channel_));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000330 lengthSamples = audioFrame.samples_per_channel_;
331
332 // Store current playout delay (to be used by ExternalRecordingInsertData).
333 playout_delay_ms_ = current_delay_ms;
334
335 return 0;
336#else
337 shared_->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
338 "ExternalPlayoutGetData() external playout is not supported");
339 return -1;
340#endif
341}
342
roosa@google.comb9e3afc2012-12-12 23:00:29 +0000343int VoEExternalMediaImpl::GetAudioFrame(int channel, int desired_sample_rate_hz,
344 AudioFrame* frame) {
345 WEBRTC_TRACE(kTraceApiCall, kTraceVoice,
346 VoEId(shared_->instance_id(), channel),
347 "GetAudioFrame(channel=%d, desired_sample_rate_hz=%d)",
348 channel, desired_sample_rate_hz);
349 if (!shared_->statistics().Initialized())
350 {
351 shared_->SetLastError(VE_NOT_INITED, kTraceError);
352 return -1;
353 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000354 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
355 voe::Channel* channelPtr = ch.channel();
roosa@google.comb9e3afc2012-12-12 23:00:29 +0000356 if (channelPtr == NULL)
357 {
358 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
359 "GetAudioFrame() failed to locate channel");
360 return -1;
361 }
362 if (!channelPtr->ExternalMixing()) {
363 shared_->SetLastError(VE_INVALID_OPERATION, kTraceError,
364 "GetAudioFrame() was called on channel that is not"
365 " externally mixed.");
366 return -1;
367 }
368 if (!channelPtr->Playing()) {
369 shared_->SetLastError(VE_INVALID_OPERATION, kTraceError,
370 "GetAudioFrame() was called on channel that is not playing.");
371 return -1;
372 }
373 if (desired_sample_rate_hz == -1) {
374 shared_->SetLastError(VE_BAD_ARGUMENT, kTraceError,
375 "GetAudioFrame() was called with bad sample rate.");
376 return -1;
377 }
378 frame->sample_rate_hz_ = desired_sample_rate_hz == 0 ? -1 :
379 desired_sample_rate_hz;
380 return channelPtr->GetAudioFrame(channel, *frame);
381}
382
383int VoEExternalMediaImpl::SetExternalMixing(int channel, bool enable) {
384 WEBRTC_TRACE(kTraceApiCall, kTraceVoice,
385 VoEId(shared_->instance_id(), channel),
386 "SetExternalMixing(channel=%d, enable=%d)", channel, enable);
387 if (!shared_->statistics().Initialized())
388 {
389 shared_->SetLastError(VE_NOT_INITED, kTraceError);
390 return -1;
391 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000392 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
393 voe::Channel* channelPtr = ch.channel();
roosa@google.comb9e3afc2012-12-12 23:00:29 +0000394 if (channelPtr == NULL)
395 {
396 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
397 "SetExternalMixing() failed to locate channel");
398 return -1;
399 }
400 return channelPtr->SetExternalMixing(enable);
401}
402
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000403#endif // WEBRTC_VOICE_ENGINE_EXTERNAL_MEDIA_API
404
405} // namespace webrtc