Home | History | Annotate | Download | only in voice_engine
      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_dtmf_impl.h"
     12 
     13 #include "webrtc/system_wrappers/include/critical_section_wrapper.h"
     14 #include "webrtc/system_wrappers/include/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 
     21 namespace webrtc {
     22 
     23 VoEDtmf* VoEDtmf::GetInterface(VoiceEngine* voiceEngine) {
     24 #ifndef WEBRTC_VOICE_ENGINE_DTMF_API
     25   return NULL;
     26 #else
     27   if (NULL == voiceEngine) {
     28     return NULL;
     29   }
     30   VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
     31   s->AddRef();
     32   return s;
     33 #endif
     34 }
     35 
     36 #ifdef WEBRTC_VOICE_ENGINE_DTMF_API
     37 
     38 VoEDtmfImpl::VoEDtmfImpl(voe::SharedData* shared)
     39     : _dtmfFeedback(true), _dtmfDirectFeedback(false), _shared(shared) {
     40   WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
     41                "VoEDtmfImpl::VoEDtmfImpl() - ctor");
     42 }
     43 
     44 VoEDtmfImpl::~VoEDtmfImpl() {
     45   WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
     46                "VoEDtmfImpl::~VoEDtmfImpl() - dtor");
     47 }
     48 
     49 int VoEDtmfImpl::SendTelephoneEvent(int channel,
     50                                     int eventCode,
     51                                     bool outOfBand,
     52                                     int lengthMs,
     53                                     int attenuationDb) {
     54   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
     55                "SendTelephoneEvent(channel=%d, eventCode=%d, outOfBand=%d,"
     56                "length=%d, attenuationDb=%d)",
     57                channel, eventCode, (int)outOfBand, lengthMs, attenuationDb);
     58   if (!_shared->statistics().Initialized()) {
     59     _shared->SetLastError(VE_NOT_INITED, kTraceError);
     60     return -1;
     61   }
     62   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
     63   voe::Channel* channelPtr = ch.channel();
     64   if (channelPtr == NULL) {
     65     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
     66                           "SendTelephoneEvent() failed to locate channel");
     67     return -1;
     68   }
     69   if (!channelPtr->Sending()) {
     70     _shared->SetLastError(VE_NOT_SENDING, kTraceError,
     71                           "SendTelephoneEvent() sending is not active");
     72     return -1;
     73   }
     74 
     75   // Sanity check
     76   const int maxEventCode = outOfBand ? static_cast<int>(kMaxTelephoneEventCode)
     77                                      : static_cast<int>(kMaxDtmfEventCode);
     78   const bool testFailed = ((eventCode < 0) || (eventCode > maxEventCode) ||
     79                            (lengthMs < kMinTelephoneEventDuration) ||
     80                            (lengthMs > kMaxTelephoneEventDuration) ||
     81                            (attenuationDb < kMinTelephoneEventAttenuation) ||
     82                            (attenuationDb > kMaxTelephoneEventAttenuation));
     83   if (testFailed) {
     84     _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
     85                           "SendTelephoneEvent() invalid parameter(s)");
     86     return -1;
     87   }
     88 
     89   const bool isDtmf = (eventCode >= 0) && (eventCode <= kMaxDtmfEventCode);
     90   const bool playDtmfToneDirect =
     91       isDtmf && (_dtmfFeedback && _dtmfDirectFeedback);
     92 
     93   if (playDtmfToneDirect) {
     94     // Mute the microphone signal while playing back the tone directly.
     95     // This is to reduce the risk of introducing echo from the added output.
     96     _shared->transmit_mixer()->UpdateMuteMicrophoneTime(lengthMs);
     97 
     98     // Play out local feedback tone directly (same approach for both inband
     99     // and outband).
    100     // Reduce the length of the the tone with 80ms to reduce risk of echo.
    101     // For non-direct feedback, outband and inband cases are handled
    102     // differently.
    103     _shared->output_mixer()->PlayDtmfTone(eventCode, lengthMs - 80,
    104                                           attenuationDb);
    105   }
    106 
    107   if (outOfBand) {
    108     // The RTP/RTCP module will always deliver OnPlayTelephoneEvent when
    109     // an event is transmitted. It is up to the VoE to utilize it or not.
    110     // This flag ensures that feedback/playout is enabled; however, the
    111     // channel object must still parse out the Dtmf events (0-15) from
    112     // all possible events (0-255).
    113     const bool playDTFMEvent = (_dtmfFeedback && !_dtmfDirectFeedback);
    114 
    115     return channelPtr->SendTelephoneEventOutband(eventCode, lengthMs,
    116                                                  attenuationDb, playDTFMEvent);
    117   } else {
    118     // For Dtmf tones, we want to ensure that inband tones are played out
    119     // in sync with the transmitted audio. This flag is utilized by the
    120     // channel object to determine if the queued Dtmf e vent shall also
    121     // be fed to the output mixer in the same step as input audio is
    122     // replaced by inband Dtmf tones.
    123     const bool playDTFMEvent =
    124         (isDtmf && _dtmfFeedback && !_dtmfDirectFeedback);
    125 
    126     return channelPtr->SendTelephoneEventInband(eventCode, lengthMs,
    127                                                 attenuationDb, playDTFMEvent);
    128   }
    129 }
    130 
    131 int VoEDtmfImpl::SetSendTelephoneEventPayloadType(int channel,
    132                                                   unsigned char type) {
    133   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    134                "SetSendTelephoneEventPayloadType(channel=%d, type=%u)", channel,
    135                type);
    136   if (!_shared->statistics().Initialized()) {
    137     _shared->SetLastError(VE_NOT_INITED, kTraceError);
    138     return -1;
    139   }
    140   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
    141   voe::Channel* channelPtr = ch.channel();
    142   if (channelPtr == NULL) {
    143     _shared->SetLastError(
    144         VE_CHANNEL_NOT_VALID, kTraceError,
    145         "SetSendTelephoneEventPayloadType() failed to locate channel");
    146     return -1;
    147   }
    148   return channelPtr->SetSendTelephoneEventPayloadType(type);
    149 }
    150 
    151 int VoEDtmfImpl::GetSendTelephoneEventPayloadType(int channel,
    152                                                   unsigned char& type) {
    153   if (!_shared->statistics().Initialized()) {
    154     _shared->SetLastError(VE_NOT_INITED, kTraceError);
    155     return -1;
    156   }
    157   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
    158   voe::Channel* channelPtr = ch.channel();
    159   if (channelPtr == NULL) {
    160     _shared->SetLastError(
    161         VE_CHANNEL_NOT_VALID, kTraceError,
    162         "GetSendTelephoneEventPayloadType() failed to locate channel");
    163     return -1;
    164   }
    165   return channelPtr->GetSendTelephoneEventPayloadType(type);
    166 }
    167 
    168 int VoEDtmfImpl::PlayDtmfTone(int eventCode, int lengthMs, int attenuationDb) {
    169   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    170                "PlayDtmfTone(eventCode=%d, lengthMs=%d, attenuationDb=%d)",
    171                eventCode, lengthMs, attenuationDb);
    172 
    173   if (!_shared->statistics().Initialized()) {
    174     _shared->SetLastError(VE_NOT_INITED, kTraceError);
    175     return -1;
    176   }
    177   if (!_shared->audio_device()->Playing()) {
    178     _shared->SetLastError(VE_NOT_PLAYING, kTraceError,
    179                           "PlayDtmfTone() no channel is playing out");
    180     return -1;
    181   }
    182   if ((eventCode < kMinDtmfEventCode) || (eventCode > kMaxDtmfEventCode) ||
    183       (lengthMs < kMinTelephoneEventDuration) ||
    184       (lengthMs > kMaxTelephoneEventDuration) ||
    185       (attenuationDb < kMinTelephoneEventAttenuation) ||
    186       (attenuationDb > kMaxTelephoneEventAttenuation)) {
    187     _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
    188                           "PlayDtmfTone() invalid tone parameter(s)");
    189     return -1;
    190   }
    191   return _shared->output_mixer()->PlayDtmfTone(eventCode, lengthMs,
    192                                                attenuationDb);
    193 }
    194 
    195 int VoEDtmfImpl::SetDtmfFeedbackStatus(bool enable, bool directFeedback) {
    196   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    197                "SetDtmfFeedbackStatus(enable=%d, directFeeback=%d)",
    198                (int)enable, (int)directFeedback);
    199 
    200   CriticalSectionScoped sc(_shared->crit_sec());
    201 
    202   _dtmfFeedback = enable;
    203   _dtmfDirectFeedback = directFeedback;
    204 
    205   return 0;
    206 }
    207 
    208 int VoEDtmfImpl::GetDtmfFeedbackStatus(bool& enabled, bool& directFeedback) {
    209   CriticalSectionScoped sc(_shared->crit_sec());
    210 
    211   enabled = _dtmfFeedback;
    212   directFeedback = _dtmfDirectFeedback;
    213   return 0;
    214 }
    215 #endif  // #ifdef WEBRTC_VOICE_ENGINE_DTMF_API
    216 
    217 }  // namespace webrtc
    218