|
|
|
@ -7,8 +7,10 @@ |
|
|
|
|
|
|
|
int _log_facility_rtcp; |
|
|
|
int _log_facility_cdr; |
|
|
|
int _log_facility_dtmf; |
|
|
|
struct rtpengine_config rtpe_config; |
|
|
|
struct poller *rtpe_poller; |
|
|
|
GString *dtmf_logs; |
|
|
|
|
|
|
|
static str *sdup(char *s) { |
|
|
|
str *r = g_slice_alloc(sizeof(*r)); |
|
|
|
@ -35,6 +37,8 @@ static struct call call; |
|
|
|
static struct sdp_ng_flags flags; |
|
|
|
static struct call_media *media_A; |
|
|
|
static struct call_media *media_B; |
|
|
|
struct call_monologue ml_A; |
|
|
|
struct call_monologue ml_B; |
|
|
|
static GQueue rtp_types; |
|
|
|
|
|
|
|
#define start() __start(__FILE__, __LINE__) |
|
|
|
@ -47,10 +51,18 @@ static void __start(const char *file, int line) { |
|
|
|
ssrc_B = 2345; |
|
|
|
call = (struct call) {{0,},}; |
|
|
|
call.ssrc_hash = create_ssrc_hash_call(); |
|
|
|
call.tags = g_hash_table_new(g_str_hash, g_str_equal); |
|
|
|
str_init(&call.callid, "test-call"); |
|
|
|
flags = (struct sdp_ng_flags) {0,}; |
|
|
|
bencode_buffer_init(&call.buffer); |
|
|
|
media_A = call_media_new(&call); // originator |
|
|
|
media_B = call_media_new(&call); // output destination |
|
|
|
ml_A = (struct call_monologue) {0,}; |
|
|
|
str_init(&ml_A.tag, "tag_A"); |
|
|
|
media_A->monologue = &ml_A; |
|
|
|
ml_B = (struct call_monologue) {0,}; |
|
|
|
str_init(&ml_B.tag, "tag_B"); |
|
|
|
media_B->monologue = &ml_B; |
|
|
|
g_queue_init(&rtp_types); // parsed from received SDP |
|
|
|
flags.codec_strip = g_hash_table_new_full(str_hash, str_equal, str_slice_free, NULL); |
|
|
|
flags.codec_mask = g_hash_table_new_full(str_hash, str_equal, str_slice_free, NULL); |
|
|
|
@ -105,21 +117,34 @@ static void __expect(const char *file, int line, GQueue *dumper, const char *cod |
|
|
|
#define packet_seq_ts(side, pt_in, pload, rtp_ts, rtp_seq, pt_out, pload_exp, ts_exp, fatal) \ |
|
|
|
__packet_seq_ts( __FILE__, __LINE__, media_ ## side, pt_in, (str) STR_CONST_INIT(pload), \ |
|
|
|
(str) STR_CONST_INIT(pload_exp), ssrc_ ## side, rtp_ts, rtp_seq, pt_out, \ |
|
|
|
ts_exp, fatal) |
|
|
|
ts_exp, 1, fatal) |
|
|
|
|
|
|
|
#define packet_seq_exp(side, pt_in, pload, rtp_ts, rtp_seq, pt_out, pload_exp, ts_diff_exp) \ |
|
|
|
__packet_seq_ts( __FILE__, __LINE__, media_ ## side, pt_in, (str) STR_CONST_INIT(pload), \ |
|
|
|
(str) STR_CONST_INIT(pload_exp), ssrc_ ## side, rtp_ts, rtp_seq, pt_out, \ |
|
|
|
-1, ts_diff_exp, 1) |
|
|
|
|
|
|
|
static void __packet_seq_ts(const char *file, int line, struct call_media *media, long long pt_in, str pload, |
|
|
|
str pload_exp, uint32_t ssrc, long long rtp_ts, long long rtp_seq, long long pt_out, |
|
|
|
long long ts_exp, int fatal) |
|
|
|
long long ts_exp, int seq_diff_exp, int fatal) |
|
|
|
{ |
|
|
|
printf("running test %s:%i\n", file, line); |
|
|
|
struct codec_handler *h = codec_handler_get(media, pt_in); |
|
|
|
struct codec_handler *h = codec_handler_get(media, pt_in & 0x7f); |
|
|
|
str pl = pload; |
|
|
|
str pl_exp = pload_exp; |
|
|
|
|
|
|
|
// from media_packet_rtp() |
|
|
|
struct media_packet mp = { |
|
|
|
.call = &call, |
|
|
|
.media = media, |
|
|
|
.ssrc_in = get_ssrc_ctx(ssrc, call.ssrc_hash, SSRC_DIR_INPUT), |
|
|
|
}; |
|
|
|
// from __stream_ssrc() |
|
|
|
if (!MEDIA_ISSET(media, TRANSCODE)) |
|
|
|
mp.ssrc_in->ssrc_map_out = ntohl(ssrc); |
|
|
|
mp.ssrc_out = get_ssrc_ctx(mp.ssrc_in->ssrc_map_out, call.ssrc_hash, SSRC_DIR_OUTPUT); |
|
|
|
payload_tracker_add(&mp.ssrc_in->tracker, pt_in & 0x7f); |
|
|
|
|
|
|
|
int packet_len = sizeof(struct rtp_header) + pl.len; |
|
|
|
char *packet = malloc(packet_len); |
|
|
|
struct rtp_header *rtp = (void *) packet; |
|
|
|
@ -166,8 +191,8 @@ static void __packet_seq_ts(const char *file, int line, struct call_media *media |
|
|
|
uint32_t ts = ntohl(rtp->timestamp); |
|
|
|
uint16_t seq = ntohs(rtp->seq_num); |
|
|
|
uint32_t ssrc = ntohl(rtp->ssrc); |
|
|
|
uint32_t ssrc_pt = ssrc ^ pt_out; |
|
|
|
ssrc_pt ^= pt_in << 8; /* XXX this is actually wrong and should be removed. it's a workaround for a bug */ |
|
|
|
uint32_t ssrc_pt = ssrc ^ (pt_out & 0x7f); |
|
|
|
ssrc_pt ^= (pt_in & 0x7f) << 8; /* XXX this is actually wrong and should be removed. it's a workaround for a bug */ |
|
|
|
printf("RTP SSRC %x seq %u TS %u PT %u\n", (unsigned int) ssrc, |
|
|
|
(unsigned int) seq, (unsigned int) ts, (unsigned int) rtp->m_pt); |
|
|
|
if (g_hash_table_contains(rtp_ts_ht, GUINT_TO_POINTER(ssrc_pt))) { |
|
|
|
@ -184,7 +209,7 @@ static void __packet_seq_ts(const char *file, int line, struct call_media *media |
|
|
|
GUINT_TO_POINTER(ssrc_pt))); |
|
|
|
uint16_t diff = seq - old_seq; |
|
|
|
printf("RTP seq diff: %u\n", (unsigned int) diff); |
|
|
|
assert(diff == 1); |
|
|
|
assert(diff == seq_diff_exp); |
|
|
|
} |
|
|
|
g_hash_table_insert(rtp_seq_ht, GUINT_TO_POINTER(ssrc_pt), GUINT_TO_POINTER(seq)); |
|
|
|
if (str_shift(&cp->s, sizeof(struct rtp_header))) |
|
|
|
@ -212,6 +237,24 @@ static void end() { |
|
|
|
g_hash_table_destroy(rtp_seq_ht); |
|
|
|
} |
|
|
|
|
|
|
|
static void dtmf(const char *s) { |
|
|
|
if (!dtmf_logs) { |
|
|
|
if (strlen(s) != 0) |
|
|
|
abort(); |
|
|
|
return; |
|
|
|
} |
|
|
|
if (strlen(s) != dtmf_logs->len) { |
|
|
|
printf("DTMF mismatch: \"%s\" != \"%s\"\n", s, dtmf_logs->str); |
|
|
|
abort(); |
|
|
|
} |
|
|
|
if (memcmp(s, dtmf_logs->str, dtmf_logs->len) != 0) { |
|
|
|
printf("DTMF mismatch: \"%s\" != \"%s\"\n", s, dtmf_logs->str); |
|
|
|
abort(); |
|
|
|
} |
|
|
|
printf("DTMF log ok; contents: \"%s\"\n", dtmf_logs->str); |
|
|
|
g_string_assign(dtmf_logs, ""); |
|
|
|
} |
|
|
|
|
|
|
|
#define PCMU_payload "\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00" |
|
|
|
#define PCMA_payload "\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a" |
|
|
|
#define G722_payload "\x23\x84\x20\x84\x20\x84\x04\x84\x04\x04\x84\x04\x84\x04\x84\x05\x85\x46\x87\x48\xc8\x48\x88\x48\xc8\x49\x8a\x4b\xcc\x4c\x8c\x4c\xcc\x4c\x8c\x4d\xce\x50\xcf\x51\x90\x50\xcf\x12\xd1\x52\xd2\x54\x91\x52\xd2\x54\x92\x54\xd3\x56\x93\xd6\x94\xd4\x93\xd7\xd5\x55\x94\x55\xd5\x55\xd4\x56\xd5\x17\xd7\x5a\x95\xd7\x97\xd9\xd4\x16\x58\x57\x98\xd5\xd7\x5b\x96\xda\xd6\x1b\x57\x5a\xd6\x1a\x57\x5b\x98\xd6\xd8\x56\x98\xd7\xd9\x5a\x95\xdb\xd6\x1c\x52\x5e\xd7\x5c\x93\xdf\x99\xd5\xd7\x5f\xd9\x14\x56\x7f\x92\xda\xd9\x5c\x92\xdd\xd7\x5d\x92\xff\xd6\x5a\x96\xdc\xd5\x18\x56\x7e\xd2\x5e\x96\xde\x94\xd8\xd8\x58\xd3\x79\x93\xfb\x90\xdc\xd6\x5b\xdd\x58\x96\xff" |
|
|
|
@ -220,6 +263,7 @@ static void end() { |
|
|
|
|
|
|
|
int main() { |
|
|
|
codeclib_init(0); |
|
|
|
srandom(time(NULL)); |
|
|
|
|
|
|
|
// plain |
|
|
|
start(); |
|
|
|
@ -603,5 +647,112 @@ int main() { |
|
|
|
expect(B, send, "9/G722/8000 8/PCMA/8000"); |
|
|
|
end(); |
|
|
|
|
|
|
|
_log_facility_dtmf = 1; // dummy enabler |
|
|
|
|
|
|
|
// plain DTMF passthrough w/o transcoding |
|
|
|
start(); |
|
|
|
sdp_pt(8, PCMA, 8000); |
|
|
|
sdp_pt(101, telephone-event, 8000); |
|
|
|
offer(); |
|
|
|
expect(A, recv, ""); |
|
|
|
expect(A, send, "8/PCMA/8000 101/telephone-event/8000"); |
|
|
|
expect(B, recv, "8/PCMA/8000 101/telephone-event/8000"); |
|
|
|
expect(B, send, ""); |
|
|
|
sdp_pt(8, PCMA, 8000); |
|
|
|
sdp_pt(101, telephone-event, 8000); |
|
|
|
answer(); |
|
|
|
expect(A, recv, "8/PCMA/8000 101/telephone-event/8000"); |
|
|
|
expect(A, send, "8/PCMA/8000 101/telephone-event/8000"); |
|
|
|
expect(B, recv, "8/PCMA/8000 101/telephone-event/8000"); |
|
|
|
expect(B, send, "8/PCMA/8000 101/telephone-event/8000"); |
|
|
|
packet_seq(A, 8, PCMA_payload, 1000000, 200, 8, PCMA_payload); |
|
|
|
// start with marker |
|
|
|
packet_seq(A, 101 | 0x80, "\x08\x0a\x00\xa0", 1000160, 201, 101 | 0x80, "\x08\x0a\x00\xa0"); |
|
|
|
dtmf(""); |
|
|
|
// continuous event with increasing length |
|
|
|
// XXX check output ts, seq, ssrc |
|
|
|
packet_seq(A, 101, "\x08\x0a\x01\x40", 1000160, 202, 101, "\x08\x0a\x01\x40"); |
|
|
|
packet_seq(A, 101, "\x08\x0a\x01\xe0", 1000160, 203, 101, "\x08\x0a\x01\xe0"); |
|
|
|
packet_seq(A, 101, "\x08\x0a\x02\x80", 1000160, 204, 101, "\x08\x0a\x02\x80"); |
|
|
|
dtmf(""); |
|
|
|
// end |
|
|
|
packet_seq(A, 101, "\x08\x8a\x03\x20", 1000160, 205, 101, "\x08\x8a\x03\x20"); |
|
|
|
dtmf("{\"callid\":\"test-call\",\"source_tag\":\"tag_A\",\"tags\":[],\"type\":\"DTMF\",\"timestamp\":0,\"source_ip\":\"(null)\",\"event\":8,\"duration\":100,\"volume\":10}"); |
|
|
|
packet_seq_exp(A, 101, "\x08\x8a\x03\x20", 1000160, 205, 101, "\x08\x8a\x03\x20", 0); |
|
|
|
packet_seq_exp(A, 101, "\x08\x8a\x03\x20", 1000160, 205, 101, "\x08\x8a\x03\x20", 0); |
|
|
|
dtmf(""); |
|
|
|
// send some more audio |
|
|
|
packet_seq_exp(A, 8, PCMA_payload, 1000960, 206, 8, PCMA_payload, 6); // expected seq is 200+6 for PT 8 |
|
|
|
packet_seq(A, 8, PCMA_payload, 1001120, 207, 8, PCMA_payload); |
|
|
|
// start with marker |
|
|
|
packet_seq_exp(A, 101 | 0x80, "\x05\x0a\x00\xa0", 1001280, 208, 101 | 0x80, "\x05\x0a\x00\xa0", 3); // expected seq is 205+3 for PT 101 |
|
|
|
dtmf(""); |
|
|
|
// continuous event with increasing length |
|
|
|
packet_seq(A, 101, "\x05\x0a\x01\x40", 1001280, 209, 101, "\x05\x0a\x01\x40"); |
|
|
|
packet_seq(A, 101, "\x05\x0a\x01\xe0", 1001280, 210, 101, "\x05\x0a\x01\xe0"); |
|
|
|
dtmf(""); |
|
|
|
// end |
|
|
|
packet_seq(A, 101, "\x05\x8a\x02\x80", 1001280, 211, 101, "\x05\x8a\x02\x80"); |
|
|
|
dtmf("{\"callid\":\"test-call\",\"source_tag\":\"tag_A\",\"tags\":[],\"type\":\"DTMF\",\"timestamp\":0,\"source_ip\":\"(null)\",\"event\":5,\"duration\":80,\"volume\":10}"); |
|
|
|
packet_seq_exp(A, 101, "\x05\x8a\x02\x80", 1001280, 211, 101, "\x05\x8a\x02\x80", 0); |
|
|
|
packet_seq_exp(A, 101, "\x05\x8a\x02\x80", 1001280, 211, 101, "\x05\x8a\x02\x80", 0); |
|
|
|
dtmf(""); |
|
|
|
// final audio RTP test |
|
|
|
packet_seq_exp(A, 8, PCMA_payload, 1000960, 212, 8, PCMA_payload, 5); // expected seq is 207+5 for PT 8 |
|
|
|
end(); |
|
|
|
|
|
|
|
// DTMF passthrough w/ transcoding |
|
|
|
start(); |
|
|
|
sdp_pt(8, PCMA, 8000); |
|
|
|
sdp_pt(101, telephone-event, 8000); |
|
|
|
transcode(PCMU); |
|
|
|
offer(); |
|
|
|
expect(A, recv, ""); |
|
|
|
expect(A, send, "8/PCMA/8000 101/telephone-event/8000"); |
|
|
|
expect(B, recv, "8/PCMA/8000 101/telephone-event/8000 0/PCMU/8000"); |
|
|
|
expect(B, send, ""); |
|
|
|
sdp_pt(0, PCMU, 8000); |
|
|
|
sdp_pt(101, telephone-event, 8000); |
|
|
|
answer(); |
|
|
|
expect(A, recv, "8/PCMA/8000 101/telephone-event/8000"); |
|
|
|
expect(A, send, "8/PCMA/8000 101/telephone-event/8000"); |
|
|
|
expect(B, recv, "101/telephone-event/8000 0/PCMU/8000"); |
|
|
|
expect(B, send, "0/PCMU/8000 101/telephone-event/8000"); |
|
|
|
packet_seq(A, 8, PCMA_payload, 1000000, 200, 0, PCMU_payload); |
|
|
|
// start with marker |
|
|
|
packet_seq(A, 101 | 0x80, "\x08\x0a\x00\xa0", 1000160, 201, 101 | 0x80, "\x08\x0a\x00\xa0"); |
|
|
|
dtmf(""); |
|
|
|
// continuous event with increasing length |
|
|
|
// XXX check output ts, seq, ssrc |
|
|
|
packet_seq(A, 101, "\x08\x0a\x01\x40", 1000160, 202, 101, "\x08\x0a\x01\x40"); |
|
|
|
packet_seq(A, 101, "\x08\x0a\x01\xe0", 1000160, 203, 101, "\x08\x0a\x01\xe0"); |
|
|
|
packet_seq(A, 101, "\x08\x0a\x02\x80", 1000160, 204, 101, "\x08\x0a\x02\x80"); |
|
|
|
dtmf(""); |
|
|
|
// end |
|
|
|
packet_seq(A, 101, "\x08\x8a\x03\x20", 1000160, 205, 101, "\x08\x8a\x03\x20"); |
|
|
|
dtmf("{\"callid\":\"test-call\",\"source_tag\":\"tag_A\",\"tags\":[],\"type\":\"DTMF\",\"timestamp\":0,\"source_ip\":\"(null)\",\"event\":8,\"duration\":100,\"volume\":10}"); |
|
|
|
packet_seq_exp(A, 101, "\x08\x8a\x03\x20", 1000160, 205, 101, "\x08\x8a\x03\x20", 0); |
|
|
|
packet_seq_exp(A, 101, "\x08\x8a\x03\x20", 1000160, 205, 101, "\x08\x8a\x03\x20", 0); |
|
|
|
dtmf(""); |
|
|
|
// send some more audio |
|
|
|
packet_seq_exp(A, 8, PCMA_payload, 1000960, 206, 0, PCMU_payload, 6); // expected seq is 200+6 for PT 8 |
|
|
|
packet_seq(A, 8, PCMA_payload, 1001120, 207, 0, PCMU_payload); |
|
|
|
// start with marker |
|
|
|
packet_seq_exp(A, 101 | 0x80, "\x05\x0a\x00\xa0", 1001280, 208, 101 | 0x80, "\x05\x0a\x00\xa0", 3); // expected seq is 205+3 for PT 101 |
|
|
|
dtmf(""); |
|
|
|
// continuous event with increasing length |
|
|
|
packet_seq(A, 101, "\x05\x0a\x01\x40", 1001280, 209, 101, "\x05\x0a\x01\x40"); |
|
|
|
packet_seq(A, 101, "\x05\x0a\x01\xe0", 1001280, 210, 101, "\x05\x0a\x01\xe0"); |
|
|
|
dtmf(""); |
|
|
|
// end |
|
|
|
packet_seq(A, 101, "\x05\x8a\x02\x80", 1001280, 211, 101, "\x05\x8a\x02\x80"); |
|
|
|
dtmf("{\"callid\":\"test-call\",\"source_tag\":\"tag_A\",\"tags\":[],\"type\":\"DTMF\",\"timestamp\":0,\"source_ip\":\"(null)\",\"event\":5,\"duration\":80,\"volume\":10}"); |
|
|
|
packet_seq_exp(A, 101, "\x05\x8a\x02\x80", 1001280, 211, 101, "\x05\x8a\x02\x80", 0); |
|
|
|
packet_seq_exp(A, 101, "\x05\x8a\x02\x80", 1001280, 211, 101, "\x05\x8a\x02\x80", 0); |
|
|
|
dtmf(""); |
|
|
|
// final audio RTP test |
|
|
|
packet_seq_exp(A, 8, PCMA_payload, 1000960, 212, 0, PCMU_payload, 5); // expected seq is 207+5 for PT 8 |
|
|
|
end(); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |