1470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* 29a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@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 11b7edd065306329309dac6767fe4914c185f941f8turaj@webrtc.org#include "webrtc/voice_engine/voe_dtmf_impl.h" 12470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 1398f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/critical_section_wrapper.h" 1498f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/trace.h" 15b7edd065306329309dac6767fe4914c185f941f8turaj@webrtc.org#include "webrtc/voice_engine/channel.h" 16b7edd065306329309dac6767fe4914c185f941f8turaj@webrtc.org#include "webrtc/voice_engine/include/voe_errors.h" 17b7edd065306329309dac6767fe4914c185f941f8turaj@webrtc.org#include "webrtc/voice_engine/output_mixer.h" 18b7edd065306329309dac6767fe4914c185f941f8turaj@webrtc.org#include "webrtc/voice_engine/transmit_mixer.h" 19b7edd065306329309dac6767fe4914c185f941f8turaj@webrtc.org#include "webrtc/voice_engine/voice_engine_impl.h" 20470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 21470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comnamespace webrtc { 22470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 230d266054acece70259fc1e85026194154f41e5a0Jelena MarusicVoEDtmf* VoEDtmf::GetInterface(VoiceEngine* voiceEngine) { 24470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#ifndef WEBRTC_VOICE_ENGINE_DTMF_API 250d266054acece70259fc1e85026194154f41e5a0Jelena Marusic return NULL; 26470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#else 270d266054acece70259fc1e85026194154f41e5a0Jelena Marusic if (NULL == voiceEngine) { 280d266054acece70259fc1e85026194154f41e5a0Jelena Marusic return NULL; 290d266054acece70259fc1e85026194154f41e5a0Jelena Marusic } 300d266054acece70259fc1e85026194154f41e5a0Jelena Marusic VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine); 310d266054acece70259fc1e85026194154f41e5a0Jelena Marusic s->AddRef(); 320d266054acece70259fc1e85026194154f41e5a0Jelena Marusic return s; 33470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif 34470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 35470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 36470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#ifdef WEBRTC_VOICE_ENGINE_DTMF_API 37470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 380d266054acece70259fc1e85026194154f41e5a0Jelena MarusicVoEDtmfImpl::VoEDtmfImpl(voe::SharedData* shared) 390d266054acece70259fc1e85026194154f41e5a0Jelena Marusic : _dtmfFeedback(true), _dtmfDirectFeedback(false), _shared(shared) { 400d266054acece70259fc1e85026194154f41e5a0Jelena Marusic WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1), 410d266054acece70259fc1e85026194154f41e5a0Jelena Marusic "VoEDtmfImpl::VoEDtmfImpl() - ctor"); 42470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 43470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 440d266054acece70259fc1e85026194154f41e5a0Jelena MarusicVoEDtmfImpl::~VoEDtmfImpl() { 450d266054acece70259fc1e85026194154f41e5a0Jelena Marusic WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1), 460d266054acece70259fc1e85026194154f41e5a0Jelena Marusic "VoEDtmfImpl::~VoEDtmfImpl() - dtor"); 47470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 48470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 49470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint VoEDtmfImpl::SendTelephoneEvent(int channel, 50f81f9f8c2a18fb20ee60406ece45ff3210367ff9andrew@webrtc.org int eventCode, 51470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com bool outOfBand, 52470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com int lengthMs, 530d266054acece70259fc1e85026194154f41e5a0Jelena Marusic int attenuationDb) { 540d266054acece70259fc1e85026194154f41e5a0Jelena Marusic WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 550d266054acece70259fc1e85026194154f41e5a0Jelena Marusic "SendTelephoneEvent(channel=%d, eventCode=%d, outOfBand=%d," 560d266054acece70259fc1e85026194154f41e5a0Jelena Marusic "length=%d, attenuationDb=%d)", 570d266054acece70259fc1e85026194154f41e5a0Jelena Marusic channel, eventCode, (int)outOfBand, lengthMs, attenuationDb); 580d266054acece70259fc1e85026194154f41e5a0Jelena Marusic if (!_shared->statistics().Initialized()) { 590d266054acece70259fc1e85026194154f41e5a0Jelena Marusic _shared->SetLastError(VE_NOT_INITED, kTraceError); 600d266054acece70259fc1e85026194154f41e5a0Jelena Marusic return -1; 610d266054acece70259fc1e85026194154f41e5a0Jelena Marusic } 620d266054acece70259fc1e85026194154f41e5a0Jelena Marusic voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); 630d266054acece70259fc1e85026194154f41e5a0Jelena Marusic voe::Channel* channelPtr = ch.channel(); 640d266054acece70259fc1e85026194154f41e5a0Jelena Marusic if (channelPtr == NULL) { 650d266054acece70259fc1e85026194154f41e5a0Jelena Marusic _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 660d266054acece70259fc1e85026194154f41e5a0Jelena Marusic "SendTelephoneEvent() failed to locate channel"); 670d266054acece70259fc1e85026194154f41e5a0Jelena Marusic return -1; 680d266054acece70259fc1e85026194154f41e5a0Jelena Marusic } 690d266054acece70259fc1e85026194154f41e5a0Jelena Marusic if (!channelPtr->Sending()) { 700d266054acece70259fc1e85026194154f41e5a0Jelena Marusic _shared->SetLastError(VE_NOT_SENDING, kTraceError, 710d266054acece70259fc1e85026194154f41e5a0Jelena Marusic "SendTelephoneEvent() sending is not active"); 720d266054acece70259fc1e85026194154f41e5a0Jelena Marusic return -1; 730d266054acece70259fc1e85026194154f41e5a0Jelena Marusic } 740d266054acece70259fc1e85026194154f41e5a0Jelena Marusic 750d266054acece70259fc1e85026194154f41e5a0Jelena Marusic // Sanity check 760d266054acece70259fc1e85026194154f41e5a0Jelena Marusic const int maxEventCode = outOfBand ? static_cast<int>(kMaxTelephoneEventCode) 770d266054acece70259fc1e85026194154f41e5a0Jelena Marusic : static_cast<int>(kMaxDtmfEventCode); 780d266054acece70259fc1e85026194154f41e5a0Jelena Marusic const bool testFailed = ((eventCode < 0) || (eventCode > maxEventCode) || 790d266054acece70259fc1e85026194154f41e5a0Jelena Marusic (lengthMs < kMinTelephoneEventDuration) || 800d266054acece70259fc1e85026194154f41e5a0Jelena Marusic (lengthMs > kMaxTelephoneEventDuration) || 810d266054acece70259fc1e85026194154f41e5a0Jelena Marusic (attenuationDb < kMinTelephoneEventAttenuation) || 820d266054acece70259fc1e85026194154f41e5a0Jelena Marusic (attenuationDb > kMaxTelephoneEventAttenuation)); 830d266054acece70259fc1e85026194154f41e5a0Jelena Marusic if (testFailed) { 840d266054acece70259fc1e85026194154f41e5a0Jelena Marusic _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError, 850d266054acece70259fc1e85026194154f41e5a0Jelena Marusic "SendTelephoneEvent() invalid parameter(s)"); 860d266054acece70259fc1e85026194154f41e5a0Jelena Marusic return -1; 870d266054acece70259fc1e85026194154f41e5a0Jelena Marusic } 880d266054acece70259fc1e85026194154f41e5a0Jelena Marusic 890d266054acece70259fc1e85026194154f41e5a0Jelena Marusic const bool isDtmf = (eventCode >= 0) && (eventCode <= kMaxDtmfEventCode); 900d266054acece70259fc1e85026194154f41e5a0Jelena Marusic const bool playDtmfToneDirect = 910d266054acece70259fc1e85026194154f41e5a0Jelena Marusic isDtmf && (_dtmfFeedback && _dtmfDirectFeedback); 920d266054acece70259fc1e85026194154f41e5a0Jelena Marusic 930d266054acece70259fc1e85026194154f41e5a0Jelena Marusic if (playDtmfToneDirect) { 940d266054acece70259fc1e85026194154f41e5a0Jelena Marusic // Mute the microphone signal while playing back the tone directly. 950d266054acece70259fc1e85026194154f41e5a0Jelena Marusic // This is to reduce the risk of introducing echo from the added output. 960d266054acece70259fc1e85026194154f41e5a0Jelena Marusic _shared->transmit_mixer()->UpdateMuteMicrophoneTime(lengthMs); 970d266054acece70259fc1e85026194154f41e5a0Jelena Marusic 980d266054acece70259fc1e85026194154f41e5a0Jelena Marusic // Play out local feedback tone directly (same approach for both inband 990d266054acece70259fc1e85026194154f41e5a0Jelena Marusic // and outband). 1000d266054acece70259fc1e85026194154f41e5a0Jelena Marusic // Reduce the length of the the tone with 80ms to reduce risk of echo. 1010d266054acece70259fc1e85026194154f41e5a0Jelena Marusic // For non-direct feedback, outband and inband cases are handled 1020d266054acece70259fc1e85026194154f41e5a0Jelena Marusic // differently. 1030d266054acece70259fc1e85026194154f41e5a0Jelena Marusic _shared->output_mixer()->PlayDtmfTone(eventCode, lengthMs - 80, 1040d266054acece70259fc1e85026194154f41e5a0Jelena Marusic attenuationDb); 1050d266054acece70259fc1e85026194154f41e5a0Jelena Marusic } 1060d266054acece70259fc1e85026194154f41e5a0Jelena Marusic 1070d266054acece70259fc1e85026194154f41e5a0Jelena Marusic if (outOfBand) { 1080d266054acece70259fc1e85026194154f41e5a0Jelena Marusic // The RTP/RTCP module will always deliver OnPlayTelephoneEvent when 1090d266054acece70259fc1e85026194154f41e5a0Jelena Marusic // an event is transmitted. It is up to the VoE to utilize it or not. 1100d266054acece70259fc1e85026194154f41e5a0Jelena Marusic // This flag ensures that feedback/playout is enabled; however, the 1110d266054acece70259fc1e85026194154f41e5a0Jelena Marusic // channel object must still parse out the Dtmf events (0-15) from 1120d266054acece70259fc1e85026194154f41e5a0Jelena Marusic // all possible events (0-255). 1130d266054acece70259fc1e85026194154f41e5a0Jelena Marusic const bool playDTFMEvent = (_dtmfFeedback && !_dtmfDirectFeedback); 1140d266054acece70259fc1e85026194154f41e5a0Jelena Marusic 1150d266054acece70259fc1e85026194154f41e5a0Jelena Marusic return channelPtr->SendTelephoneEventOutband(eventCode, lengthMs, 1160d266054acece70259fc1e85026194154f41e5a0Jelena Marusic attenuationDb, playDTFMEvent); 1170d266054acece70259fc1e85026194154f41e5a0Jelena Marusic } else { 1180d266054acece70259fc1e85026194154f41e5a0Jelena Marusic // For Dtmf tones, we want to ensure that inband tones are played out 1190d266054acece70259fc1e85026194154f41e5a0Jelena Marusic // in sync with the transmitted audio. This flag is utilized by the 1200d266054acece70259fc1e85026194154f41e5a0Jelena Marusic // channel object to determine if the queued Dtmf e vent shall also 1210d266054acece70259fc1e85026194154f41e5a0Jelena Marusic // be fed to the output mixer in the same step as input audio is 1220d266054acece70259fc1e85026194154f41e5a0Jelena Marusic // replaced by inband Dtmf tones. 1230d266054acece70259fc1e85026194154f41e5a0Jelena Marusic const bool playDTFMEvent = 1240d266054acece70259fc1e85026194154f41e5a0Jelena Marusic (isDtmf && _dtmfFeedback && !_dtmfDirectFeedback); 1250d266054acece70259fc1e85026194154f41e5a0Jelena Marusic 1260d266054acece70259fc1e85026194154f41e5a0Jelena Marusic return channelPtr->SendTelephoneEventInband(eventCode, lengthMs, 1270d266054acece70259fc1e85026194154f41e5a0Jelena Marusic attenuationDb, playDTFMEvent); 1280d266054acece70259fc1e85026194154f41e5a0Jelena Marusic } 129470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 130470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 131470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint VoEDtmfImpl::SetSendTelephoneEventPayloadType(int channel, 1320d266054acece70259fc1e85026194154f41e5a0Jelena Marusic unsigned char type) { 1330d266054acece70259fc1e85026194154f41e5a0Jelena Marusic WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 1340d266054acece70259fc1e85026194154f41e5a0Jelena Marusic "SetSendTelephoneEventPayloadType(channel=%d, type=%u)", channel, 1350d266054acece70259fc1e85026194154f41e5a0Jelena Marusic type); 1360d266054acece70259fc1e85026194154f41e5a0Jelena Marusic if (!_shared->statistics().Initialized()) { 1370d266054acece70259fc1e85026194154f41e5a0Jelena Marusic _shared->SetLastError(VE_NOT_INITED, kTraceError); 1380d266054acece70259fc1e85026194154f41e5a0Jelena Marusic return -1; 1390d266054acece70259fc1e85026194154f41e5a0Jelena Marusic } 1400d266054acece70259fc1e85026194154f41e5a0Jelena Marusic voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); 1410d266054acece70259fc1e85026194154f41e5a0Jelena Marusic voe::Channel* channelPtr = ch.channel(); 1420d266054acece70259fc1e85026194154f41e5a0Jelena Marusic if (channelPtr == NULL) { 1430d266054acece70259fc1e85026194154f41e5a0Jelena Marusic _shared->SetLastError( 1440d266054acece70259fc1e85026194154f41e5a0Jelena Marusic VE_CHANNEL_NOT_VALID, kTraceError, 1450d266054acece70259fc1e85026194154f41e5a0Jelena Marusic "SetSendTelephoneEventPayloadType() failed to locate channel"); 1460d266054acece70259fc1e85026194154f41e5a0Jelena Marusic return -1; 1470d266054acece70259fc1e85026194154f41e5a0Jelena Marusic } 1480d266054acece70259fc1e85026194154f41e5a0Jelena Marusic return channelPtr->SetSendTelephoneEventPayloadType(type); 149470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 150470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 151470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint VoEDtmfImpl::GetSendTelephoneEventPayloadType(int channel, 1520d266054acece70259fc1e85026194154f41e5a0Jelena Marusic unsigned char& type) { 1530d266054acece70259fc1e85026194154f41e5a0Jelena Marusic if (!_shared->statistics().Initialized()) { 1540d266054acece70259fc1e85026194154f41e5a0Jelena Marusic _shared->SetLastError(VE_NOT_INITED, kTraceError); 1550d266054acece70259fc1e85026194154f41e5a0Jelena Marusic return -1; 1560d266054acece70259fc1e85026194154f41e5a0Jelena Marusic } 1570d266054acece70259fc1e85026194154f41e5a0Jelena Marusic voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); 1580d266054acece70259fc1e85026194154f41e5a0Jelena Marusic voe::Channel* channelPtr = ch.channel(); 1590d266054acece70259fc1e85026194154f41e5a0Jelena Marusic if (channelPtr == NULL) { 1600d266054acece70259fc1e85026194154f41e5a0Jelena Marusic _shared->SetLastError( 1610d266054acece70259fc1e85026194154f41e5a0Jelena Marusic VE_CHANNEL_NOT_VALID, kTraceError, 1620d266054acece70259fc1e85026194154f41e5a0Jelena Marusic "GetSendTelephoneEventPayloadType() failed to locate channel"); 1630d266054acece70259fc1e85026194154f41e5a0Jelena Marusic return -1; 1640d266054acece70259fc1e85026194154f41e5a0Jelena Marusic } 1650d266054acece70259fc1e85026194154f41e5a0Jelena Marusic return channelPtr->GetSendTelephoneEventPayloadType(type); 166470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 167470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 1680d266054acece70259fc1e85026194154f41e5a0Jelena Marusicint VoEDtmfImpl::PlayDtmfTone(int eventCode, int lengthMs, int attenuationDb) { 1690d266054acece70259fc1e85026194154f41e5a0Jelena Marusic WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 1700d266054acece70259fc1e85026194154f41e5a0Jelena Marusic "PlayDtmfTone(eventCode=%d, lengthMs=%d, attenuationDb=%d)", 1710d266054acece70259fc1e85026194154f41e5a0Jelena Marusic eventCode, lengthMs, attenuationDb); 1720d266054acece70259fc1e85026194154f41e5a0Jelena Marusic 1730d266054acece70259fc1e85026194154f41e5a0Jelena Marusic if (!_shared->statistics().Initialized()) { 1740d266054acece70259fc1e85026194154f41e5a0Jelena Marusic _shared->SetLastError(VE_NOT_INITED, kTraceError); 1750d266054acece70259fc1e85026194154f41e5a0Jelena Marusic return -1; 1760d266054acece70259fc1e85026194154f41e5a0Jelena Marusic } 1770d266054acece70259fc1e85026194154f41e5a0Jelena Marusic if (!_shared->audio_device()->Playing()) { 1780d266054acece70259fc1e85026194154f41e5a0Jelena Marusic _shared->SetLastError(VE_NOT_PLAYING, kTraceError, 1790d266054acece70259fc1e85026194154f41e5a0Jelena Marusic "PlayDtmfTone() no channel is playing out"); 1800d266054acece70259fc1e85026194154f41e5a0Jelena Marusic return -1; 1810d266054acece70259fc1e85026194154f41e5a0Jelena Marusic } 1820d266054acece70259fc1e85026194154f41e5a0Jelena Marusic if ((eventCode < kMinDtmfEventCode) || (eventCode > kMaxDtmfEventCode) || 1830d266054acece70259fc1e85026194154f41e5a0Jelena Marusic (lengthMs < kMinTelephoneEventDuration) || 1840d266054acece70259fc1e85026194154f41e5a0Jelena Marusic (lengthMs > kMaxTelephoneEventDuration) || 1850d266054acece70259fc1e85026194154f41e5a0Jelena Marusic (attenuationDb < kMinTelephoneEventAttenuation) || 1860d266054acece70259fc1e85026194154f41e5a0Jelena Marusic (attenuationDb > kMaxTelephoneEventAttenuation)) { 1870d266054acece70259fc1e85026194154f41e5a0Jelena Marusic _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError, 1880d266054acece70259fc1e85026194154f41e5a0Jelena Marusic "PlayDtmfTone() invalid tone parameter(s)"); 1890d266054acece70259fc1e85026194154f41e5a0Jelena Marusic return -1; 1900d266054acece70259fc1e85026194154f41e5a0Jelena Marusic } 1910d266054acece70259fc1e85026194154f41e5a0Jelena Marusic return _shared->output_mixer()->PlayDtmfTone(eventCode, lengthMs, 192851becd00ce814f0e02a5c5a56ac0322a7f9494dtommi@webrtc.org attenuationDb); 193470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 194470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 1950d266054acece70259fc1e85026194154f41e5a0Jelena Marusicint VoEDtmfImpl::SetDtmfFeedbackStatus(bool enable, bool directFeedback) { 1960d266054acece70259fc1e85026194154f41e5a0Jelena Marusic WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 1970d266054acece70259fc1e85026194154f41e5a0Jelena Marusic "SetDtmfFeedbackStatus(enable=%d, directFeeback=%d)", 1980d266054acece70259fc1e85026194154f41e5a0Jelena Marusic (int)enable, (int)directFeedback); 199470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 2000d266054acece70259fc1e85026194154f41e5a0Jelena Marusic CriticalSectionScoped sc(_shared->crit_sec()); 201470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 2020d266054acece70259fc1e85026194154f41e5a0Jelena Marusic _dtmfFeedback = enable; 2030d266054acece70259fc1e85026194154f41e5a0Jelena Marusic _dtmfDirectFeedback = directFeedback; 204470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 2050d266054acece70259fc1e85026194154f41e5a0Jelena Marusic return 0; 206470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 207470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 2080d266054acece70259fc1e85026194154f41e5a0Jelena Marusicint VoEDtmfImpl::GetDtmfFeedbackStatus(bool& enabled, bool& directFeedback) { 2090d266054acece70259fc1e85026194154f41e5a0Jelena Marusic CriticalSectionScoped sc(_shared->crit_sec()); 210470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 2110d266054acece70259fc1e85026194154f41e5a0Jelena Marusic enabled = _dtmfFeedback; 2120d266054acece70259fc1e85026194154f41e5a0Jelena Marusic directFeedback = _dtmfDirectFeedback; 2130d266054acece70259fc1e85026194154f41e5a0Jelena Marusic return 0; 214470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 215470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif // #ifdef WEBRTC_VOICE_ENGINE_DTMF_API 216470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 217470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} // namespace webrtc 218