voe_external_media_impl.cc revision 79af734807109d119573ce23daa1a2bff0f0eeca
1470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/*
279af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
4470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  Use of this source code is governed by a BSD-style license
5470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  that can be found in the LICENSE file in the root of the source
6470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  tree. An additional intellectual property rights grant can be found
7470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  in the file PATENTS.  All contributing project authors may
8470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  be found in the AUTHORS file in the root of the source tree.
9470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com */
10470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
11470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "voe_external_media_impl.h"
12470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
13470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "channel.h"
14470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "critical_section_wrapper.h"
15470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "output_mixer.h"
16470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "trace.h"
17470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "transmit_mixer.h"
18470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "voice_engine_impl.h"
19470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "voe_errors.h"
20470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
21470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comnamespace webrtc {
22470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
23470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comVoEExternalMedia* VoEExternalMedia::GetInterface(VoiceEngine* voiceEngine)
24470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
25470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#ifndef WEBRTC_VOICE_ENGINE_EXTERNAL_MEDIA_API
26470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return NULL;
27470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#else
28470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (NULL == voiceEngine)
29470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
30470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return NULL;
31470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
32470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    VoiceEngineImpl* s = reinterpret_cast<VoiceEngineImpl*> (voiceEngine);
33470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    VoEExternalMediaImpl* d = s;
34470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    (*d)++;
35470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return (d);
36470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif
37470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
38470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
39470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#ifdef WEBRTC_VOICE_ENGINE_EXTERNAL_MEDIA_API
40470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
41470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comVoEExternalMediaImpl::VoEExternalMediaImpl()
42470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    : playout_delay_ms_(0)
43470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
44470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,-1),
45470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "VoEExternalMediaImpl() - ctor");
46470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
47470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
48470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comVoEExternalMediaImpl::~VoEExternalMediaImpl()
49470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
50470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,-1),
51470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "~VoEExternalMediaImpl() - dtor");
52470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
53470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
54470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint VoEExternalMediaImpl::Release()
55470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
56470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
57470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "VoEExternalMedia::Release()");
58470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    (*this)--;
59470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    int refCount = GetCount();
60470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (refCount < 0)
61470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
62470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        Reset();
63470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatistics.SetLastError(VE_INTERFACE_NOT_FOUND,
64470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                       kTraceWarning);
65470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return (-1);
66470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
67470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
68470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "VoEExternalMedia reference counter = %d", refCount);
69470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return (refCount);
70470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
71470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
72470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint VoEExternalMediaImpl::RegisterExternalMediaProcessing(
73470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    int channel,
74470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    ProcessingTypes type,
75470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    VoEMediaProcess& processObject)
76470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
77470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
78470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "RegisterExternalMediaProcessing(channel=%d, type=%d, "
79470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "processObject=0x%x)", channel, type, &processObject);
802638577f0326a5929e31411bb092274351324d49leozwang@webrtc.org    ANDROID_NOT_SUPPORTED(_engineStatistics);
81470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    IPHONE_NOT_SUPPORTED();
82470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_engineStatistics.Initialized())
83470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
84470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
85470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
86470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
87470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    switch (type)
88470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
89470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kPlaybackPerChannel:
90470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kRecordingPerChannel:
91470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
92470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            voe::ScopedChannel sc(_channelManager, channel);
93470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            voe::Channel* channelPtr = sc.ChannelPtr();
94470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            if (channelPtr == NULL)
95470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            {
96470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                _engineStatistics.SetLastError(
97470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    VE_CHANNEL_NOT_VALID, kTraceError,
98470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    "RegisterExternalMediaProcessing() "
99470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    "failed to locate channel");
100470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                return -1;
101470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            }
102470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return channelPtr->RegisterExternalMediaProcessing(type,
103470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                               processObject);
104470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
105470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kPlaybackAllChannelsMixed:
106470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
107470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return _outputMixerPtr->RegisterExternalMediaProcessing(
108470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                processObject);
109470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
110470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kRecordingAllChannelsMixed:
111470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
112470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return _transmitMixerPtr->RegisterExternalMediaProcessing(
113470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                processObject);
114470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
115470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        default:
116470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
117470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatistics.SetLastError(
118470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_ARGUMENT, kTraceError,
119470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "RegisterExternalMediaProcessing() invalid process type");
120470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
121470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
122470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
123470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
124470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
125470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
126470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint VoEExternalMediaImpl::DeRegisterExternalMediaProcessing(
127470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    int channel,
128470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    ProcessingTypes type)
129470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
130470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
131470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "DeRegisterExternalMediaProcessing(channel=%d)", channel);
1322638577f0326a5929e31411bb092274351324d49leozwang@webrtc.org    ANDROID_NOT_SUPPORTED(_engineStatistics);
133470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    IPHONE_NOT_SUPPORTED();
134470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_engineStatistics.Initialized())
135470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
136470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
137470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
138470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
139470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    switch (type)
140470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
141470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kPlaybackPerChannel:
142470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kRecordingPerChannel:
143470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
144470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            voe::ScopedChannel sc(_channelManager, channel);
145470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            voe::Channel* channelPtr = sc.ChannelPtr();
146470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            if (channelPtr == NULL)
147470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            {
148470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                _engineStatistics.SetLastError(
149470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    VE_CHANNEL_NOT_VALID, kTraceError,
150470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    "RegisterExternalMediaProcessing() "
151470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                    "failed to locate channel");
152470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                return -1;
153470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            }
154470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return channelPtr->DeRegisterExternalMediaProcessing(type);
155470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
156470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kPlaybackAllChannelsMixed:
157470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
158470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return _outputMixerPtr->DeRegisterExternalMediaProcessing();
159470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
160470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        case kRecordingAllChannelsMixed:
161470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
162470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return _transmitMixerPtr->DeRegisterExternalMediaProcessing();
163470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
164470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        default:
165470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
166470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _engineStatistics.SetLastError(
167470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                VE_INVALID_ARGUMENT, kTraceError,
168470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                "RegisterExternalMediaProcessing() invalid process type");
169470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            return -1;
170470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
171470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
172470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
173470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
174470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint VoEExternalMediaImpl::SetExternalRecordingStatus(bool enable)
175470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
176470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
177470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "SetExternalRecordingStatus(enable=%d)", enable);
1782638577f0326a5929e31411bb092274351324d49leozwang@webrtc.org    ANDROID_NOT_SUPPORTED(_engineStatistics);
179470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    IPHONE_NOT_SUPPORTED();
180470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
181470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_audioDevicePtr->Recording())
182470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
183470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatistics.SetLastError(
184470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_SENDING,
185470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            kTraceError,
186470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetExternalRecordingStatus() cannot set state while sending");
187470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
188470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
189470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _externalRecording = enable;
190470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
191470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#else
192470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _engineStatistics.SetLastError(
193470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        VE_FUNC_NOT_SUPPORTED,
194470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        kTraceError,
195470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        "SetExternalRecordingStatus() external recording is not supported");
196470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return -1;
197470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif
198470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
199470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
200470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint VoEExternalMediaImpl::ExternalRecordingInsertData(
201470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        const WebRtc_Word16 speechData10ms[],
202470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        int lengthSamples,
203470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        int samplingFreqHz,
204470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        int current_delay_ms)
205470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
206470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1),
207470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "ExternalRecordingInsertData(speechData10ms=0x%x,"
208470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 " lengthSamples=%u, samplingFreqHz=%d, current_delay_ms=%d)",
209470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 &speechData10ms[0], lengthSamples, samplingFreqHz,
210470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              current_delay_ms);
2112638577f0326a5929e31411bb092274351324d49leozwang@webrtc.org    ANDROID_NOT_SUPPORTED(_engineStatistics);
212470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    IPHONE_NOT_SUPPORTED();
213470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
214470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
215470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_engineStatistics.Initialized())
216470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
217470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
218470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
219470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
220470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_externalRecording)
221470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
222470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       _engineStatistics.SetLastError(
223470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com           VE_INVALID_OPERATION,
224470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com           kTraceError,
225470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com           "ExternalRecordingInsertData() external recording is not enabled");
226470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
227470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
228470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (NumOfSendingChannels() == 0)
229470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
230470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatistics.SetLastError(
231470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_SENDING,
232470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            kTraceError,
233470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetExternalRecordingStatus() no channel is sending");
234470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
235470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
236470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if ((16000 != samplingFreqHz) && (32000 != samplingFreqHz) &&
237470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (48000 != samplingFreqHz) && (44000 != samplingFreqHz))
238470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
239470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com         _engineStatistics.SetLastError(
240470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com             VE_INVALID_ARGUMENT,
241470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com             kTraceError,
242470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com             "SetExternalRecordingStatus() invalid sample rate");
243470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
244470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
245470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if ((0 == lengthSamples) ||
246470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        ((lengthSamples % (samplingFreqHz / 100)) != 0))
247470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
248470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com         _engineStatistics.SetLastError(
249470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com             VE_INVALID_ARGUMENT,
250470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com             kTraceError,
251470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com             "SetExternalRecordingStatus() invalid buffer size");
252470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
253470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
254470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (current_delay_ms < 0)
255470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
256470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatistics.SetLastError(
257470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT,
258470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            kTraceError,
259470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetExternalRecordingStatus() invalid delay)");
260470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
261470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
262470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
263470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WebRtc_UWord16 blockSize = samplingFreqHz / 100;
264470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WebRtc_UWord32 nBlocks = lengthSamples / blockSize;
265470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WebRtc_Word16 totalDelayMS = 0;
266470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WebRtc_UWord16 playoutDelayMS = 0;
267470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
268470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for (WebRtc_UWord32 i = 0; i < nBlocks; i++)
269470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
270470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (!_externalPlayout)
271470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
272470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Use real playout delay if external playout is not enabled.
27379af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org            if (_audioDevicePtr->PlayoutDelay(&playoutDelayMS) != 0) {
27479af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org              _engineStatistics.SetLastError(
27579af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org                  VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
27679af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org                  "PlayoutDelay() unable to get the playout delay");
27779af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org            }
278470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            totalDelayMS = current_delay_ms + playoutDelayMS;
279470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
280470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        else
281470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
282470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Use stored delay value given the last call
283470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // to ExternalPlayoutGetData.
284470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            totalDelayMS = current_delay_ms + playout_delay_ms_;
285470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Compensate for block sizes larger than 10ms
286470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            totalDelayMS -= (WebRtc_Word16)(i*10);
287470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            if (totalDelayMS < 0)
288470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                totalDelayMS = 0;
289470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
290470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _transmitMixerPtr->PrepareDemux(
291470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            (const WebRtc_Word8*)(&speechData10ms[i*blockSize]),
292470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            blockSize,
293470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            1,
294470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            samplingFreqHz,
295470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            totalDelayMS,
296470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            0,
297470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            0);
298470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
299470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _transmitMixerPtr->DemuxAndMix();
300470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _transmitMixerPtr->EncodeAndSend();
301470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
302470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
303470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#else
304470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       _engineStatistics.SetLastError(
305470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        VE_FUNC_NOT_SUPPORTED,
306470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        kTraceError,
307470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        "ExternalRecordingInsertData() external recording is not supported");
308470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return -1;
309470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif
310470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
311470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
312470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint VoEExternalMediaImpl::SetExternalPlayoutStatus(bool enable)
313470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
314470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
315470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "SetExternalPlayoutStatus(enable=%d)", enable);
3162638577f0326a5929e31411bb092274351324d49leozwang@webrtc.org    ANDROID_NOT_SUPPORTED(_engineStatistics);
317470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    IPHONE_NOT_SUPPORTED();
318470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
319470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_audioDevicePtr->Playing())
320470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
321470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatistics.SetLastError(
322470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_ALREADY_SENDING,
323470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            kTraceError,
324470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "SetExternalPlayoutStatus() cannot set state while playing");
325470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
326470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
327470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _externalPlayout = enable;
328470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
329470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#else
330470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _engineStatistics.SetLastError(
331470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        VE_FUNC_NOT_SUPPORTED,
332470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        kTraceError,
333470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        "SetExternalPlayoutStatus() external playout is not supported");
334470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return -1;
335470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif
336470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
337470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
338470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint VoEExternalMediaImpl::ExternalPlayoutGetData(
339470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WebRtc_Word16 speechData10ms[],
340470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    int samplingFreqHz,
341470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    int current_delay_ms,
342470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    int& lengthSamples)
343470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
344470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1),
345470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "ExternalPlayoutGetData(speechData10ms=0x%x, samplingFreqHz=%d"
346470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 ",  current_delay_ms=%d)", &speechData10ms[0], samplingFreqHz,
347470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 current_delay_ms);
3482638577f0326a5929e31411bb092274351324d49leozwang@webrtc.org    ANDROID_NOT_SUPPORTED(_engineStatistics);
349470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    IPHONE_NOT_SUPPORTED();
350470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
351470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_engineStatistics.Initialized())
352470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
353470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
354470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
355470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
356470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_externalPlayout)
357470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
358470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       _engineStatistics.SetLastError(
359470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com           VE_INVALID_OPERATION,
360470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com           kTraceError,
361470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com           "ExternalPlayoutGetData() external playout is not enabled");
362470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
363470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
364470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if ((16000 != samplingFreqHz) && (32000 != samplingFreqHz) &&
365470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (48000 != samplingFreqHz) && (44000 != samplingFreqHz))
366470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
367470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatistics.SetLastError(
368470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT,
369470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            kTraceError,
370470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "ExternalPlayoutGetData() invalid sample rate");
371470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
372470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
373470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (current_delay_ms < 0)
374470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
375470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatistics.SetLastError(
376470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT,
377470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            kTraceError,
378470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "ExternalPlayoutGetData() invalid delay)");
379470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
380470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
381470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
382470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    AudioFrame audioFrame;
383470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
384470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Retrieve mixed output at the specified rate
385470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputMixerPtr->MixActiveChannels();
386470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputMixerPtr->DoOperationsOnCombinedSignal();
387470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputMixerPtr->GetMixedAudio(samplingFreqHz, 1, audioFrame);
388470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
389470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Deliver audio (PCM) samples to the external sink
390470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    memcpy(speechData10ms,
391470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com           audioFrame._payloadData,
392470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com           sizeof(WebRtc_Word16)*(audioFrame._payloadDataLengthInSamples));
393470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    lengthSamples = audioFrame._payloadDataLengthInSamples;
394470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
395470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Store current playout delay (to be used by ExternalRecordingInsertData).
396470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    playout_delay_ms_ = current_delay_ms;
397470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
398470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
399470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#else
400470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _engineStatistics.SetLastError(
401470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       VE_FUNC_NOT_SUPPORTED,
402470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       kTraceError,
403470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       "ExternalPlayoutGetData() external playout is not supported");
404470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return -1;
405470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif
406470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
407470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
408470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif  // WEBRTC_VOICE_ENGINE_EXTERNAL_MEDIA_API
409470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
410470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}  // namespace webrtc
411