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