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