The patch attached seems to work for me. I used the patch from the original authors at http://sourceforge.net/p/sipp/patches/50/ and updated it slightly so all credit goes to them. Is there any formal process to have this considered for inclusion on the main source code?

H


On 23/07/14 14:07, Horaci Macias wrote:
Hi everybody,

I'm having trouble playing more than 1 DTMF using pcap_play.
Has anybody had any success doing this, if possible without having to create a single pcap with multiple rtpevents in it?

searching on this I found http://sourceforge.net/p/sipp/patches/50/ which seems to address the limitation. I tried patching sipp but for some reason things are not working as expected.
Has anybody been able to do this?

thanks,
--

Horaci




diff --git a/actions.cpp b/actions.cpp
index 70e61ee..d78ba47 100644
--- a/actions.cpp
+++ b/actions.cpp
@@ -149,6 +149,8 @@ void CAction::afficheInfo()
 #ifdef PCAPPLAY
     } else if ((M_action == E_AT_PLAY_PCAP_AUDIO) || (M_action == E_AT_PLAY_PCAP_VIDEO)) {
         printf("Type[%d] - file[%s]", M_action, M_pcapArgs->file);
+  } else if (M_action == E_AT_PLAY_DTMF) {
+      printf("Type[%d] - play DTMF digits [%s]", M_action, M_message_str[0]);
 #endif
 
 #ifdef RTP_STREAM
diff --git a/actions.hpp b/actions.hpp
index 30573be..ea8bbeb 100644
--- a/actions.hpp
+++ b/actions.hpp
@@ -72,6 +72,7 @@ public:
 #ifdef PCAPPLAY
         E_AT_PLAY_PCAP_AUDIO,
         E_AT_PLAY_PCAP_VIDEO,
+        E_AT_PLAY_DTMF,
 #endif
 #ifdef RTP_STREAM
       E_AT_RTP_STREAM_PAUSE,
diff --git a/call.cpp b/call.cpp
index 0d3d525..1d240b1 100644
--- a/call.cpp
+++ b/call.cpp
@@ -524,6 +524,8 @@ void call::init(scenario * call_scenario, struct sipp_socket *socket, struct soc
 
 #ifdef PCAPPLAY
     hasMediaInformation = 0;
+    play_args_a.last_seq_no = 1200;
+    play_args_v.last_seq_no = 2400;
 #endif
 
     call_remote_socket = NULL;
@@ -3794,14 +3796,36 @@ call::T_ActionResult call::executeAction(char * msg, message *curmsg)
             }
 #ifdef PCAPPLAY
         } else if ((currentAction->getActionType() == CAction::E_AT_PLAY_PCAP_AUDIO) ||
-                   (currentAction->getActionType() == CAction::E_AT_PLAY_PCAP_VIDEO)) {
+                   (currentAction->getActionType() == CAction::E_AT_PLAY_PCAP_VIDEO) ||
+                   (currentAction->getActionType() == CAction::E_AT_PLAY_DTMF)) {
             play_args_t *play_args = 0;
-            if (currentAction->getActionType() == CAction::E_AT_PLAY_PCAP_AUDIO) {
+            if (currentAction->getActionType() == CAction::E_AT_PLAY_PCAP_AUDIO ||
+             (currentAction->getActionType() == CAction::E_AT_PLAY_DTMF)) {
+
                 play_args = &(this->play_args_a);
             } else if (currentAction->getActionType() == CAction::E_AT_PLAY_PCAP_VIDEO) {
                 play_args = &(this->play_args_v);
             }
-            play_args->pcap = currentAction->getPcapPkts();
+
+            // existing media thread could be using play_args, so we have to kill it before modifying parameters
+            if (media_thread != 0) {
+              // If a media_thread is already active, kill it before starting a new one
+              pthread_cancel(media_thread);
+              pthread_join(media_thread, NULL);
+              media_thread = 0;
+            }
+
+
+            if (currentAction->getActionType() == CAction::E_AT_PLAY_DTMF) {
+              char * digits = createSendingMessage(currentAction->getMessage(), -2 /* do not add crlf*/);
+              play_args->pcap = (pcap_pkts *) malloc(sizeof(pcap_pkts));
+      	      play_args->last_seq_no += parse_dtmf_play_args(digits, play_args->pcap, play_args->last_seq_no);
+	      play_args->free_pcap_when_done = 1;
+            } else {
+	      play_args->pcap = currentAction->getPcapPkts();
+              play_args->free_pcap_when_done = 0;
+            }
+
             /* port number is set in [auto_]media_port interpolation */
             if (media_ip_is_ipv6) {
                 struct sockaddr_in6 *from = (struct sockaddr_in6 *)(void *) &(play_args->from);
@@ -3818,13 +3842,6 @@ call::T_ActionResult call::executeAction(char * msg, message *curmsg)
 #ifndef PTHREAD_STACK_MIN
 #define PTHREAD_STACK_MIN	16384
 #endif
-            //pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
-            if (media_thread != 0) {
-                // If a media_thread is already active, kill it before starting a new one
-                pthread_cancel(media_thread);
-                pthread_join(media_thread, NULL);
-                media_thread = 0;
-            }
             int ret = pthread_create(&media_thread, &attr, send_wrapper,
                                      (void *) play_args);
             if(ret)
diff --git a/prepare_pcap.c b/prepare_pcap.c
index 92754b6..6dd2008 100644
--- a/prepare_pcap.c
+++ b/prepare_pcap.c
@@ -198,4 +198,170 @@ int prepare_pkts(char *file, pcap_pkts *pkts)
 
     return 0;
 }
+struct rtphdr {
+  unsigned char csicnt:4;
+  unsigned int extension:1;
+  unsigned int  padding:1;
+  unsigned char version:2;
 
+  unsigned char payload_type:7;
+  unsigned int marker:1;
+
+  u_int16_t seqno;
+  u_int32_t timestamp;
+  u_int32_t ssrcid;
+};
+
+struct rtpevent {
+  unsigned char event_id;
+
+  unsigned char volume:6;
+  unsigned int reserved:1;
+  unsigned int end_of_event:1;
+
+  u_int16_t duration;
+};
+
+struct dtmfpacket {
+  struct udphdr udp;
+  struct rtphdr rtp;
+  struct rtpevent dtmf;
+};
+
+static u_long dtmf_ssrcid = 0x01020304;
+
+void fill_default_dtmf(struct dtmfpacket * dtmfpacket, int marker, int seqno, int ts, char digit, int eoe, int duration) {
+  u_long pktlen = sizeof(struct dtmfpacket);
+
+#if defined(__HPUX) || defined(__DARWIN) || (defined __CYGWIN) || defined(__FreeBSD__)
+  dtmfpacket->udp.uh_ulen = htons(pktlen);
+  dtmfpacket->udp.uh_sum = 0 ;
+  dtmfpacket->udp.uh_sport = 0;
+  dtmfpacket->udp.uh_dport = 0;
+#else
+  dtmfpacket->udp.len = htons(pktlen);
+  dtmfpacket->udp.check = 0;
+  dtmfpacket->udp.source = 0;
+  dtmfpacket->udp.dest = 0;
+#endif
+  dtmfpacket->rtp.version = 2;
+  dtmfpacket->rtp.padding = 0;
+  dtmfpacket->rtp.extension = 0;
+  dtmfpacket->rtp.csicnt = 0;
+  dtmfpacket->rtp.marker = marker;
+  dtmfpacket->rtp.payload_type = 0x60;
+  dtmfpacket->rtp.seqno = htons(seqno);
+  dtmfpacket->rtp.timestamp = htonl(ts);
+  dtmfpacket->rtp.ssrcid = dtmf_ssrcid;
+
+  dtmfpacket->dtmf.event_id = digit;
+  dtmfpacket->dtmf.end_of_event = eoe;
+  dtmfpacket->dtmf.volume = 10;
+  dtmfpacket->dtmf.duration = htons(duration * 8);
+}
+
+/* prepare a dtmf pcap 
+ */
+int prepare_dtmf(char *digits, pcap_pkts *pkts, u_int16_t start_seq_no) {
+  int n_pkts = 0;
+  int n_digits = 0;
+  u_long pktlen = sizeof(struct dtmfpacket);
+  pcap_pkt *pkt_index;
+  char * digit;
+  int i;
+  char * comma;
+  unsigned long tone_len = 200;
+  
+  dtmf_ssrcid++;
+
+  pkts->pkts = NULL;
+
+  if (comma = strchr(digits,',')) {
+    tone_len = atol(comma+1);
+    if (tone_len < 50 || tone_len > 2000) tone_len = 200;
+    *comma = '\0';
+  }
+
+  for(digit = digits; *digit; digit++) {
+    unsigned char uc_digit;
+    struct dtmfpacket * dtmfpacket;
+    unsigned long cur_tone_len = 0;
+    unsigned long ts;
+    
+    if (*digit >= '0' && *digit <= '9') {
+      uc_digit = *digit - '0';
+    } else if (*digit == '*') {
+      uc_digit = 10;
+    } else if (*digit == '#') {
+      uc_digit = 11;
+    } else {
+      continue;
+    }
+      
+    while (cur_tone_len < tone_len) {
+      ts = (n_digits + 1) * tone_len * 2 + cur_tone_len;
+
+      pkts->pkts = (pcap_pkt *) realloc(pkts->pkts, sizeof(*(pkts->pkts)) * (n_pkts + 1));
+      if (!pkts->pkts) {
+        ERROR("Can't re-allocate memory for dtmf pcap pkt");
+      }
+
+      pkt_index = pkts->pkts + n_pkts;
+      pkt_index->pktlen = pktlen;
+      pkt_index->ts.tv_sec = ts / 1000;
+      pkt_index->ts.tv_usec = (ts % 1000) * 1000;
+      pkt_index->data = (unsigned char *) malloc(pktlen);
+      if (!pkt_index->data) {
+        ERROR("Can't allocate memory for pcap pkt data");
+      }
+
+      dtmfpacket = (struct dtmfpacket*)pkt_index->data;
+
+      fill_default_dtmf(dtmfpacket, n_pkts == 0, n_pkts + start_seq_no, n_digits * tone_len * 2 + 24000, uc_digit, 0, cur_tone_len);
+
+#if defined(__HPUX) || defined(__DARWIN) || (defined __CYGWIN) || defined(__FreeBSD__)
+      pkt_index->partial_check = check((u_int16_t *) &dtmfpacket->udp.uh_ulen, pktlen - 4) + ntohs(IPPROTO_UDP + pktlen);
+#else
+      pkt_index->partial_check = check((u_int16_t *) &dtmfpacket->udp.len, pktlen - 4) + ntohs(IPPROTO_UDP + pktlen);
+#endif
+      n_pkts++;
+      cur_tone_len += 20;
+    }
+    
+    for(i = 0; i < 3; i++) {
+      ts = (n_digits + 1) * tone_len * 2 + tone_len + i + 1;
+      pkts->pkts = (pcap_pkt *) realloc(pkts->pkts, sizeof(*(pkts->pkts)) * (n_pkts + 1));
+      if (!pkts->pkts) {
+        ERROR("Can't re-allocate memory for dtmf pcap pkt");
+      }
+
+      pkt_index = pkts->pkts + n_pkts;
+      pkt_index->pktlen = pktlen;
+      pkt_index->ts.tv_sec = ts / 1000;
+      pkt_index->ts.tv_usec = (ts % 1000) * 1000;
+      pkt_index->data = (unsigned char *) malloc(pktlen);
+      if (!pkt_index->data) {
+        ERROR("Can't allocate memory for pcap pkt data");
+      }
+
+      dtmfpacket = (struct dtmfpacket*)pkt_index->data;
+
+      fill_default_dtmf(dtmfpacket, 0, n_pkts + start_seq_no, n_digits * tone_len * 2 + 24000, uc_digit, 1, tone_len);
+
+#if defined(__HPUX) || defined(__DARWIN) || (defined __CYGWIN) || defined(__FreeBSD__)
+      pkt_index->partial_check = check((u_int16_t *) &dtmfpacket->udp.uh_ulen, pktlen - 4) + ntohs(IPPROTO_UDP + pktlen);
+#else
+      pkt_index->partial_check = check((u_int16_t *) &dtmfpacket->udp.len, pktlen - 4) + ntohs(IPPROTO_UDP + pktlen);
+#endif
+      n_pkts++;
+    }
+
+    n_digits++;
+  }
+
+  pkts->max = pkts->pkts + n_pkts;
+  pkts->max_length = pktlen;
+  pkts->base = 0;
+
+  return n_pkts;
+}
diff --git a/prepare_pcap.h b/prepare_pcap.h
index 5886f8b..968d82c 100644
--- a/prepare_pcap.h
+++ b/prepare_pcap.h
@@ -71,6 +71,7 @@ extern "C" {
     int check(u_int16_t *, int);
     u_int16_t checksum_carry(int);
     int prepare_pkts(char *, pcap_pkts *);
+    int prepare_dtmf(char *, pcap_pkts *, u_int16_t start_seq_no);
 #ifdef __cplusplus
 }
 #endif
diff --git a/scenario.cpp b/scenario.cpp
index 9508093..a3dd47a 100644
--- a/scenario.cpp
+++ b/scenario.cpp
@@ -1618,11 +1618,17 @@ void scenario::parseAction(CActions *actions)
                 tmpAction->setPcapArgs(ptr);
                 tmpAction->setActionType(CAction::E_AT_PLAY_PCAP_VIDEO);
                 hasMedia = 1;
+            } else if ((ptr = xp_get_value((char * ) "play_dtmf"))) {
+                tmpAction->setMessage(ptr);
+                tmpAction->setActionType(CAction::E_AT_PLAY_DTMF);
+	        hasMedia = 1;
 #else
             } else if ((ptr = xp_get_value((char *) "play_pcap_audio"))) {
                 ERROR("play_pcap_audio requires pcap support! Please recompile SIPp");
             } else if ((ptr = xp_get_value((char *) "play_pcap_video"))) {
                 ERROR("play_pcap_video requires pcap support! Please recompile SIPp");
+            } else if ((ptr = xp_get_value((char *) "play_dtmf"))) {
+                ERROR("play_dtmf requires pcap support! Please recompile SIPp");
 #endif
 #ifdef RTP_STREAM
       } else if ((ptr = xp_get_value((char *) "rtp_stream"))) {
diff --git a/send_packets.c b/send_packets.c
index 02ba2fd..cf7aeef 100644
--- a/send_packets.c
+++ b/send_packets.c
@@ -102,6 +102,13 @@ parse_play_args (char *buffer, pcap_pkts *pkts)
     return 1;
 }
 
+int parse_dtmf_play_args(char * buffer, pcap_pkts *pkts, u_int16_t start_seq_no) 
+{
+    pkts->file = strdup(buffer);
+    return prepare_dtmf(pkts->file, pkts, start_seq_no);
+}
+
+
 void hexdump(char *p, int s)
 {
     int i;
@@ -122,8 +129,22 @@ void send_packets_cleanup(void *arg)
     close(*sock);
 }
 
+void send_packets_pcap_cleanup(void * arg) 
+{
+    play_args_t * play_args = (play_args_t *) arg;
+
+    if (play_args->free_pcap_when_done) 
+    {
+        free(play_args->pcap);
+        play_args->pcap = NULL;
+    }
+}
+
 int send_packets (play_args_t * play_args)
 {
+    pthread_cleanup_push(send_packets_pcap_cleanup, ((void*)play_args));
+    {
+
     int ret, sock, port_diff;
     pcap_pkt *pkt_index, *pkt_max;
     uint16_t *from_port, *to_port;
@@ -249,6 +270,8 @@ int send_packets (play_args_t * play_args)
     }
 
     /* Closing the socket is handled by pthread_cleanup_push()/pthread_cleanup_pop() */
+        pthread_cleanup_pop(1);
+    }
     pthread_cleanup_pop(1);
     return 0;
 }
diff --git a/send_packets.h b/send_packets.h
index 4c0dc86..2aced06 100644
--- a/send_packets.h
+++ b/send_packets.h
@@ -114,6 +114,10 @@ typedef struct {
     /* Used in send_packets thread */
     struct sockaddr_storage to;
     struct sockaddr_storage from;
+
+    /* non-zero if the thread should destroy the *pcap when done playing or aborted */
+    int free_pcap_when_done; 
+    u_int16_t last_seq_no;
 } play_args_t;
 
 #ifdef __cplusplus
@@ -121,6 +125,7 @@ extern "C"
 {
 #endif
     int parse_play_args (char *, pcap_pkts *);
+    int parse_dtmf_play_args(char *, pcap_pkts *, u_int16_t start_seq_no);
     int send_packets (play_args_t *);
 #ifdef __cplusplus
 }
------------------------------------------------------------------------------
Want fast and easy access to all the code in your enterprise? Index and
search up to 200,000 lines of code with a free copy of Black Duck
Code Sight - the same software that powers the world's largest code
search on Ohloh, the Black Duck Open Hub! Try it now.
http://p.sf.net/sfu/bds
_______________________________________________
Sipp-users mailing list
Sipp-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sipp-users

Reply via email to