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