1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org/*
2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *
4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Use of this source code is governed by a BSD-style license
5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  that can be found in the LICENSE file in the root of the source
6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  tree. An additional intellectual property rights grant can be found
7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  in the file PATENTS.  All contributing project authors may
8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */
10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1115a03fd972746f234e2dd9bb5540ae0b4ad6ee82turaj@webrtc.org#include "webrtc/voice_engine/voe_dtmf_impl.h"
12b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1315a03fd972746f234e2dd9bb5540ae0b4ad6ee82turaj@webrtc.org#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
1415a03fd972746f234e2dd9bb5540ae0b4ad6ee82turaj@webrtc.org#include "webrtc/system_wrappers/interface/trace.h"
1515a03fd972746f234e2dd9bb5540ae0b4ad6ee82turaj@webrtc.org#include "webrtc/voice_engine/channel.h"
1615a03fd972746f234e2dd9bb5540ae0b4ad6ee82turaj@webrtc.org#include "webrtc/voice_engine/include/voe_errors.h"
1715a03fd972746f234e2dd9bb5540ae0b4ad6ee82turaj@webrtc.org#include "webrtc/voice_engine/output_mixer.h"
1815a03fd972746f234e2dd9bb5540ae0b4ad6ee82turaj@webrtc.org#include "webrtc/voice_engine/transmit_mixer.h"
1915a03fd972746f234e2dd9bb5540ae0b4ad6ee82turaj@webrtc.org#include "webrtc/voice_engine/voice_engine_impl.h"
20b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
21b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace webrtc {
22b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
23b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVoEDtmf* VoEDtmf::GetInterface(VoiceEngine* voiceEngine)
24b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
25b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#ifndef WEBRTC_VOICE_ENGINE_DTMF_API
26b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return NULL;
27b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#else
28b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (NULL == voiceEngine)
29b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
30b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return NULL;
31b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
32b9e5a3d589349ee55e41cb54eca4ec822018f5c5tommi@webrtc.org    VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
33b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    s->AddRef();
34b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return s;
35b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#endif
36b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
37b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
38b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#ifdef WEBRTC_VOICE_ENGINE_DTMF_API
39b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
40b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVoEDtmfImpl::VoEDtmfImpl(voe::SharedData* shared) :
41b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _dtmfFeedback(true),
42b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _dtmfDirectFeedback(false),
43b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _shared(shared)
44b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
45b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
46b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "VoEDtmfImpl::VoEDtmfImpl() - ctor");
47b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
48b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
49b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVoEDtmfImpl::~VoEDtmfImpl()
50b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
51b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
52b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "VoEDtmfImpl::~VoEDtmfImpl() - dtor");
53b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
54b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
55b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VoEDtmfImpl::SendTelephoneEvent(int channel,
56b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                    int eventCode,
57b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                    bool outOfBand,
58b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                    int lengthMs,
59b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                    int attenuationDb)
60b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
61b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
62b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "SendTelephoneEvent(channel=%d, eventCode=%d, outOfBand=%d,"
63b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "length=%d, attenuationDb=%d)",
64b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 channel, eventCode, (int)outOfBand, lengthMs, attenuationDb);
65b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_shared->statistics().Initialized())
66b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
67b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_NOT_INITED, kTraceError);
68b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
69b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
70b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
71b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::Channel* channelPtr = ch.channel();
72b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (channelPtr == NULL)
73b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
74b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
75b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "SendTelephoneEvent() failed to locate channel");
76b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
77b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
78b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!channelPtr->Sending())
79b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
80b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_NOT_SENDING, kTraceError,
81b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "SendTelephoneEvent() sending is not active");
82b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
83b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
84b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
85b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Sanity check
86b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const int maxEventCode = outOfBand ?
87b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        static_cast<int>(kMaxTelephoneEventCode) :
88b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        static_cast<int>(kMaxDtmfEventCode);
89b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const bool testFailed = ((eventCode < 0) ||
90b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        (eventCode > maxEventCode) ||
91b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        (lengthMs < kMinTelephoneEventDuration) ||
92b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        (lengthMs > kMaxTelephoneEventDuration) ||
93b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        (attenuationDb < kMinTelephoneEventAttenuation) ||
94b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        (attenuationDb > kMaxTelephoneEventAttenuation));
95b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (testFailed)
96b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
97b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
98b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "SendTelephoneEvent() invalid parameter(s)");
99b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const bool isDtmf =
103b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        (eventCode >= 0) && (eventCode <= kMaxDtmfEventCode);
104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const bool playDtmfToneDirect =
105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        isDtmf && (_dtmfFeedback && _dtmfDirectFeedback);
106b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (playDtmfToneDirect)
108b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
109b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Mute the microphone signal while playing back the tone directly.
110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // This is to reduce the risk of introducing echo from the added output.
111b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->transmit_mixer()->UpdateMuteMicrophoneTime(lengthMs);
112b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
113b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Play out local feedback tone directly (same approach for both inband
114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // and outband).
115b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Reduce the length of the the tone with 80ms to reduce risk of echo.
116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // For non-direct feedback, outband and inband cases are handled
117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // differently.
118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->output_mixer()->PlayDtmfTone(eventCode, lengthMs - 80,
119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                            attenuationDb);
120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (outOfBand)
123b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
124b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // The RTP/RTCP module will always deliver OnPlayTelephoneEvent when
125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // an event is transmitted. It is up to the VoE to utilize it or not.
126b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // This flag ensures that feedback/playout is enabled; however, the
127b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // channel object must still parse out the Dtmf events (0-15) from
128b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // all possible events (0-255).
129b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        const bool playDTFMEvent = (_dtmfFeedback && !_dtmfDirectFeedback);
130b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return channelPtr->SendTelephoneEventOutband(eventCode,
132b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                     lengthMs,
133b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                     attenuationDb,
134b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                     playDTFMEvent);
135b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
136b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else
137b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
138b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // For Dtmf tones, we want to ensure that inband tones are played out
139b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // in sync with the transmitted audio. This flag is utilized by the
140b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // channel object to determine if the queued Dtmf e vent shall also
141b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // be fed to the output mixer in the same step as input audio is
142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // replaced by inband Dtmf tones.
143b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        const bool playDTFMEvent =
144b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            (isDtmf && _dtmfFeedback && !_dtmfDirectFeedback);
145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
146b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return channelPtr->SendTelephoneEventInband(eventCode,
147b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                    lengthMs,
148b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                    attenuationDb,
149b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                    playDTFMEvent);
150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
151b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
152b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
153b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VoEDtmfImpl::SetSendTelephoneEventPayloadType(int channel,
154b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                  unsigned char type)
155b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
157b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "SetSendTelephoneEventPayloadType(channel=%d, type=%u)",
158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 channel, type);
159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_shared->statistics().Initialized())
160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_NOT_INITED, kTraceError);
162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
163b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
164b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
165b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::Channel* channelPtr = ch.channel();
166b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (channelPtr == NULL)
167b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "SetSendTelephoneEventPayloadType() failed to locate channel");
170b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
172b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return channelPtr->SetSendTelephoneEventPayloadType(type);
173b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
174b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
175b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VoEDtmfImpl::GetSendTelephoneEventPayloadType(int channel,
176b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                  unsigned char& type)
177b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "GetSendTelephoneEventPayloadType(channel=%d)", channel);
180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_shared->statistics().Initialized())
181b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
182b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_NOT_INITED, kTraceError);
183b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
184b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
185b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
186b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::Channel* channelPtr = ch.channel();
187b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (channelPtr == NULL)
188b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
189b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
190b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "GetSendTelephoneEventPayloadType() failed to locate channel");
191b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
192b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
193b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return channelPtr->GetSendTelephoneEventPayloadType(type);
194b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
195b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
196b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VoEDtmfImpl::PlayDtmfTone(int eventCode,
197b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                              int lengthMs,
198b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                              int attenuationDb)
199b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
200b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
201b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "PlayDtmfTone(eventCode=%d, lengthMs=%d, attenuationDb=%d)",
202b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 eventCode, lengthMs, attenuationDb);
203b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
204b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_shared->statistics().Initialized())
205b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
206b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_NOT_INITED, kTraceError);
207b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
208b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
209b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_shared->audio_device()->Playing())
210b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
211b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_NOT_PLAYING, kTraceError,
212b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "PlayDtmfTone() no channel is playing out");
213b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
214b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
215b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if ((eventCode < kMinDtmfEventCode) ||
216b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        (eventCode > kMaxDtmfEventCode) ||
217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        (lengthMs < kMinTelephoneEventDuration) ||
218b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        (lengthMs > kMaxTelephoneEventDuration) ||
219b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        (attenuationDb <kMinTelephoneEventAttenuation) ||
220b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        (attenuationDb > kMaxTelephoneEventAttenuation))
221b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
222b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
223b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        "PlayDtmfTone() invalid tone parameter(s)");
224b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
225b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
226b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return _shared->output_mixer()->PlayDtmfTone(eventCode, lengthMs,
227b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                               attenuationDb);
228b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
229b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
230b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VoEDtmfImpl::SetDtmfFeedbackStatus(bool enable, bool directFeedback)
231b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
232b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
233b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "SetDtmfFeedbackStatus(enable=%d, directFeeback=%d)",
234b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 (int)enable, (int)directFeedback);
235b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
236b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped sc(_shared->crit_sec());
237b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
238b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _dtmfFeedback = enable;
239b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _dtmfDirectFeedback = directFeedback;
240b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
241b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
242b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
243b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
244b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VoEDtmfImpl::GetDtmfFeedbackStatus(bool& enabled, bool& directFeedback)
245b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
246b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
247b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "GetDtmfFeedbackStatus()");
248b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
249b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped sc(_shared->crit_sec());
250b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    enabled = _dtmfFeedback;
252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    directFeedback = _dtmfDirectFeedback;
253b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
254b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
255b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        VoEId(_shared->instance_id(), -1),
256b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        "GetDtmfFeedbackStatus() => enabled=%d, directFeedback=%d",
257b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        enabled, directFeedback);
258b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
259b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
260b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
261b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VoEDtmfImpl::SetDtmfPlayoutStatus(int channel, bool enable)
262b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
263b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
264b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "SetDtmfPlayoutStatus(channel=%d, enable=%d)",
265b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 channel, enable);
266b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
267b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_shared->statistics().Initialized())
268b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
269b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_NOT_INITED, kTraceError);
270b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
271b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
272b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
273b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::Channel* channelPtr = ch.channel();
274b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (channelPtr == NULL)
275b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
276b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
277b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "SetDtmfPlayoutStatus() failed to locate channel");
278b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
279b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
280b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return channelPtr->SetDtmfPlayoutStatus(enable);
281b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
282b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
283b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VoEDtmfImpl::GetDtmfPlayoutStatus(int channel, bool& enabled)
284b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
285b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
286b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "GetDtmfPlayoutStatus(channel=%d, enabled=?)", channel);
287b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_shared->statistics().Initialized())
288b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
289b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_NOT_INITED, kTraceError);
290b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
291b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
292b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
293b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::Channel* channelPtr = ch.channel();
294b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (channelPtr == NULL)
295b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
296b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
297b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "GetDtmfPlayoutStatus() failed to locate channel");
298b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
299b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
300b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    enabled = channelPtr->DtmfPlayoutStatus();
301b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
302b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        VoEId(_shared->instance_id(), -1),
303b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        "GetDtmfPlayoutStatus() => enabled=%d", enabled);
304b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
305b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
306b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
307b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#endif  // #ifdef WEBRTC_VOICE_ENGINE_DTMF_API
308b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
309b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}  // namespace webrtc
310