Browse code

sbc:rtprelay_dtmf_filtering and rtprelay_dtmf_detection options

With the option rtprelay_dtmf_filtering=yes the SBC filters out RTP DTMF
(RFC2833 / RFC4733) packets in relayed streams.

If rtprelay_dtmf_detection=yes is set, DTMF from RTP packets is detected
and can be used to control applications, e.g. special call flows, implemented with
the extended call control API. Note that the call needs to be added to
the media processor in order for DTMF events to be processed.

Internally, if the flag force_dtmf_receiving is set for the RTP stream,
also in relay mode the DTMF packets are sent to the DTMF detection queue.

The ext cc api is extended with the onDtmf function.

Stefan Sayer authored on 05/11/2013 23:55:52
Showing 11 changed files
... ...
@@ -969,6 +969,22 @@ void CallLeg::onSessionTimeout()
969 969
   updateCallStatus(Disconnected, StatusChangeCause::SessionTimeout);
970 970
   AmB2BSession::onSessionTimeout();
971 971
 }
972
+// AmMediaSession interface from AmMediaProcessor
973
+int CallLeg::readStreams(unsigned long long ts, unsigned char *buffer) {
974
+  // skip RTP processing if in Relay mode
975
+  // (but we want to process DTMF thus we may be in media processor)
976
+  if (getRtpRelayMode()==RTP_Relay)
977
+    return 0;
978
+  return AmB2BSession::readStreams(ts, buffer);
979
+}
980
+
981
+int CallLeg::writeStreams(unsigned long long ts, unsigned char *buffer) {
982
+  // skip RTP processing if in Relay mode
983
+  // (but we want to process DTMF thus we may be in media processor)
984
+  if (getRtpRelayMode()==RTP_Relay)
985
+    return 0;
986
+  return AmB2BSession::writeStreams(ts, buffer);
987
+}
972 988
 
973 989
 void CallLeg::addNewCallee(CallLeg *callee, ConnectLegEvent *e,
974 990
 			   AmB2BSession::RTPRelayMode mode)
... ...
@@ -305,6 +305,10 @@ class CallLeg: public AmB2BSession
305 305
 
306 306
     const char* getCallStatusStr();
307 307
 
308
+    // AmMediaSession interface from AmMediaProcessor
309
+    int readStreams(unsigned long long ts, unsigned char *buffer);
310
+    int writeStreams(unsigned long long ts, unsigned char *buffer);
311
+
308 312
   public:
309 313
     /** creates A leg */
310 314
     CallLeg(AmSipDialog* p_dlg=NULL, AmSipSubscription* p_subs=NULL);
... ...
@@ -64,6 +64,7 @@ class ExtendedCCInterface
64 64
     /** called before any other processing for the event is done */
65 65
     virtual CCChainProcessing onEvent(SBCCallLeg *call, AmEvent *e) { return ContinueProcessing; }
66 66
 
67
+    virtual CCChainProcessing onDtmf(SBCCallLeg *call, int event, int duration) { return ContinueProcessing;  };
67 68
 
68 69
     // hold related functionality (seems to work best being explicitly supported
69 70
     // with API than hacking based on another callbacks)
... ...
@@ -279,6 +279,8 @@ void SBCCallLeg::applyAProfile()
279 279
 
280 280
     setRtpRelayTransparentSeqno(call_profile.rtprelay_transparent_seqno);
281 281
     setRtpRelayTransparentSSRC(call_profile.rtprelay_transparent_ssrc);
282
+    setEnableDtmfRtpFiltering(call_profile.rtprelay_dtmf_filtering);
283
+    setEnableDtmfRtpDetection(call_profile.rtprelay_dtmf_detection);
282 284
 
283 285
     if(call_profile.transcoder.isActive()) {
284 286
       setRtpRelayMode(RTP_Transcoding);
... ...
@@ -654,10 +656,16 @@ void SBCCallLeg::onOtherBye(const AmSipRequest& req)
654 656
 
655 657
 void SBCCallLeg::onDtmf(int event, int duration)
656 658
 {
659
+  DBG("received DTMF on %c-leg (%i;%i)\n", a_leg ? 'A': 'B', event, duration);
660
+
661
+  for (vector<ExtendedCCInterface*>::iterator i = cc_ext.begin(); i != cc_ext.end(); ++i) {
662
+    if ((*i)->onDtmf(this, event, duration)  == StopProcessing);
663
+    return;
664
+  }
665
+
657 666
   AmB2BMedia *ms = getMediaSession();
658 667
   if(ms) {
659
-    DBG("received DTMF on %c-leg (%i;%i)\n",
660
-	a_leg ? 'A': 'B', event, duration);
668
+    DBG("sending DTMF (%i;%i)\n", event, duration);
661 669
     ms->sendDtmf(!a_leg,event,duration);
662 670
   }
663 671
 }
... ...
@@ -356,6 +356,10 @@ bool SBCCallProfile::readFromConfiguration(const string& name,
356 356
     cfg.getParameter("rtprelay_transparent_seqno", "yes") == "yes";
357 357
   rtprelay_transparent_ssrc =
358 358
     cfg.getParameter("rtprelay_transparent_ssrc", "yes") == "yes";
359
+  rtprelay_dtmf_filtering =
360
+    cfg.getParameter("rtprelay_dtmf_filtering", "no") == "yes";
361
+  rtprelay_dtmf_detection =
362
+    cfg.getParameter("rtprelay_dtmf_detection", "no") == "yes";
359 363
 
360 364
   outbound_interface = cfg.getParameter("outbound_interface");
361 365
   aleg_outbound_interface = cfg.getParameter("aleg_outbound_interface");
... ...
@@ -476,6 +480,10 @@ bool SBCCallProfile::readFromConfiguration(const string& name,
476 480
 	   rtprelay_transparent_seqno?"transparent":"opaque");
477 481
       INFO("SBC:      RTP Relay %s SSRC\n",
478 482
 	   rtprelay_transparent_ssrc?"transparent":"opaque");
483
+      INFO("SBC:      RTP Relay RTP DTMF filtering %sabled\n",
484
+	   rtprelay_dtmf_filtering?"en":"dis");
485
+      INFO("SBC:      RTP Relay RTP DTMF detection %sabled\n",
486
+	   rtprelay_dtmf_detection?"en":"dis");
479 487
     }
480 488
 
481 489
     INFO("SBC:      SST on A leg enabled: '%s'\n", sst_aleg_enabled.empty() ?
... ...
@@ -187,6 +187,8 @@ struct SBCCallProfile
187 187
   bool msgflags_symmetric_rtp;
188 188
   bool rtprelay_transparent_seqno;
189 189
   bool rtprelay_transparent_ssrc;
190
+  bool rtprelay_dtmf_filtering;
191
+  bool rtprelay_dtmf_detection;
190 192
 
191 193
   string rtprelay_interface;
192 194
   int rtprelay_interface_value;
... ...
@@ -207,6 +207,9 @@ void AudioStreamData::initialize(AmB2BSession *session)
207 207
   stream = new AmRtpAudio(session, session->getRtpInterface());
208 208
   stream->setRtpRelayTransparentSeqno(session->getRtpRelayTransparentSeqno());
209 209
   stream->setRtpRelayTransparentSSRC(session->getRtpRelayTransparentSSRC());
210
+  stream->setRtpRelayFilterRtpDtmf(session->getEnableDtmfRtpFiltering());
211
+  if (session->getEnableDtmfRtpDetection())
212
+    stream->force_receive_dtmf = true;
210 213
   force_symmetric_rtp = session->getRtpRelayForceSymmetricRtp();
211 214
   enable_dtmf_transcoding = session->getEnableDtmfTranscoding();
212 215
   session->getLowFiPLs(lowfi_payloads);
... ...
@@ -1228,6 +1231,26 @@ void AmB2BMedia::setRtpLogger(msg_logger* _logger)
1228 1231
   for (RelayStreamIterator j = relay_streams.begin(); j != relay_streams.end(); ++j) (*j)->setLogger(logger);
1229 1232
 }
1230 1233
 
1234
+void AmB2BMedia::setRelayDTMFReceiving(bool enabled) {
1235
+  DBG("relay_streams.size() = %zd, audio_streams.size() = %zd\n", relay_streams.size(), audio.size());
1236
+  for (RelayStreamIterator j = relay_streams.begin(); j != relay_streams.end(); j++) {
1237
+    DBG("force_receive_dtmf %sabled for [%p]\n", enabled?"en":"dis", &(*j)->a);
1238
+    DBG("force_receive_dtmf %sabled for [%p]\n", enabled?"en":"dis", &(*j)->b);
1239
+    (*j)->a.force_receive_dtmf = enabled;
1240
+    (*j)->b.force_receive_dtmf = enabled;
1241
+  }
1242
+
1243
+  for (AudioStreamIterator j = audio.begin(); j != audio.end(); j++) {
1244
+    DBG("force_receive_dtmf %sabled for [%p]\n", enabled?"en":"dis", j->a.getStream());
1245
+    DBG("force_receive_dtmf %sabled for [%p]\n", enabled?"en":"dis", j->b.getStream());
1246
+    if (NULL != j->a.getStream())
1247
+      j->a.getStream()->force_receive_dtmf = enabled;
1248
+    
1249
+    if (NULL != j->b.getStream())
1250
+      j->b.getStream()->force_receive_dtmf = enabled;
1251
+  }
1252
+}
1253
+
1231 1254
 void AudioStreamData::debug()
1232 1255
 {
1233 1256
   if(stream) {
... ...
@@ -67,6 +67,12 @@ class AudioStreamData {
67 67
     /** Enables inband dtmf detection */
68 68
     bool enable_dtmf_transcoding;
69 69
 
70
+    /** Enables RTP DTMF (2833/4733) filtering */
71
+    bool enable_dtmf_rtp_filtering;
72
+
73
+    /** Enables DTMF detection with RTP DTMF (2833/4733) */
74
+    bool enable_dtmf_rtp_detection;
75
+
70 76
     /** Low fidelity payloads for which inband DTMF transcoding should be used */
71 77
     vector<SdpPayload> lowfi_payloads;
72 78
   
... ...
@@ -439,6 +445,9 @@ class AmB2BMedia: public AmMediaSession
439 445
 
440 446
     void setRtpLogger(msg_logger* _logger);
441 447
 
448
+    /** enable or disable DTMF receiving on relay streams */
449
+    void setRelayDTMFReceiving(bool enabled);
450
+
442 451
     // print debug info
443 452
     void debug();
444 453
 };
... ...
@@ -73,6 +73,8 @@ AmB2BSession::AmB2BSession(const string& other_local_tag, AmSipDialog* p_dlg,
73 73
     rtp_relay_mode(RTP_Direct),
74 74
     rtp_relay_force_symmetric_rtp(false),
75 75
     enable_dtmf_transcoding(false),
76
+    enable_dtmf_rtp_filtering(false),
77
+    enable_dtmf_rtp_detection(false),
76 78
     rtp_relay_transparent_seqno(true), rtp_relay_transparent_ssrc(true),
77 79
     est_invite_cseq(0),est_invite_other_cseq(0),
78 80
     media_session(NULL)
... ...
@@ -988,6 +990,14 @@ void AmB2BSession::setEnableDtmfTranscoding(bool enable) {
988 990
   enable_dtmf_transcoding = enable;
989 991
 }
990 992
 
993
+void AmB2BSession::setEnableDtmfRtpFiltering(bool enable) {
994
+  enable_dtmf_rtp_filtering = enable;
995
+}
996
+
997
+void AmB2BSession::setEnableDtmfRtpDetection(bool enable) {
998
+  enable_dtmf_rtp_detection = enable;
999
+}
1000
+
991 1001
 void AmB2BSession::getLowFiPLs(vector<SdpPayload>& lowfi_payloads) const {
992 1002
   lowfi_payloads = this->lowfi_payloads;
993 1003
 }
... ...
@@ -1286,6 +1296,8 @@ void AmB2BCallerSession::initializeRTPRelay(AmB2BCalleeSession* callee_session)
1286 1296
   
1287 1297
   callee_session->setRtpRelayMode(rtp_relay_mode);
1288 1298
   callee_session->setEnableDtmfTranscoding(enable_dtmf_transcoding);
1299
+  callee_session->setEnableDtmfRtpFiltering(enable_dtmf_rtp_filtering);
1300
+  callee_session->setEnableDtmfRtpDetection(enable_dtmf_rtp_detection);
1289 1301
   callee_session->setLowFiPLs(lowfi_payloads);
1290 1302
 
1291 1303
   if ((rtp_relay_mode == RTP_Relay) || (rtp_relay_mode == RTP_Transcoding)) {
... ...
@@ -273,6 +273,11 @@ private:
273 273
   /** If true, transcoded audio is injected into 
274 274
       the inband DTMF detector */
275 275
   bool enable_dtmf_transcoding;
276
+  /** filter RTP DTMF (2833 / 4733) packets */
277
+  bool enable_dtmf_rtp_filtering;
278
+  /** detect DTMF through RTP DTMF (2833 / 4733) packets */
279
+  bool enable_dtmf_rtp_detection;
280
+
276 281
   /** Low fidelity payloads for which inband DTMF 
277 282
       transcoding should be used */
278 283
   vector<SdpPayload> lowfi_payloads;
... ...
@@ -320,6 +325,8 @@ private:
320 325
   RTPRelayMode getRtpRelayMode() const { return rtp_relay_mode; }
321 326
   bool getRtpRelayForceSymmetricRtp() const { return rtp_relay_force_symmetric_rtp; }
322 327
   bool getEnableDtmfTranscoding() const { return enable_dtmf_transcoding; }
328
+  bool getEnableDtmfRtpFiltering() const { return enable_dtmf_rtp_filtering; }
329
+  bool getEnableDtmfRtpDetection() const { return enable_dtmf_rtp_detection; }
323 330
   void getLowFiPLs(vector<SdpPayload>& lowfi_payloads) const;
324 331
 
325 332
   virtual void setRtpInterface(int relay_interface);
... ...
@@ -328,6 +335,8 @@ private:
328 335
   void setRtpRelayTransparentSSRC(bool transparent);
329 336
 
330 337
   void setEnableDtmfTranscoding(bool enable);
338
+  void setEnableDtmfRtpFiltering(bool enable);
339
+  void setEnableDtmfRtpDetection(bool enable);
331 340
   void setLowFiPLs(const vector<SdpPayload>& lowfi_payloads);
332 341
   
333 342
   bool getRtpRelayTransparentSeqno() { return rtp_relay_transparent_seqno; }
... ...
@@ -403,7 +403,16 @@ rtprelay_msgflags_symmetric_rtp=yes
403 403
 
404 404
 the SBC honors this and sets symmetric RTP accordingly.
405 405
 
406
+With the option rtprelay_dtmf_filtering=yes the SBC filters out RTP DTMF
407
+(RFC2833 / RFC4733) packets in relayed streams.
406 408
 
409
+If rtprelay_dtmf_detection=yes is set, DTMF from RTP packets is detected
410
+and can be used to control applications, e.g. special call flows, implemented with
411
+the extended call control API. Note that the call needs to be added to
412
+the media processor in order for DTMF events to be processed.
413
+
414
+Transcoding
415
+-----------
407 416
 The SBC is able to do transcoding together with relaying. 
408 417
 
409 418
 To trigger transcoding you have to configure transcoder_codecs to a set