From d86208d1ed35213be59db482439fbed0d9a9eccc Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 4 Aug 2010 06:11:27 +0800 Subject: mgcp: Update to the latest code drop. --- include/mgcp/mgcp.h | 15 ++++-------- include/mgcp/mgcp_internal.h | 19 +++++++++++++++ src/mgcp/mgcp_network.c | 56 +++++++++++++++++++++++++++++++++++++------- src/mgcp/mgcp_protocol.c | 13 +++++++++- 4 files changed, 84 insertions(+), 19 deletions(-) diff --git a/include/mgcp/mgcp.h b/include/mgcp/mgcp.h index 9bbf554..ef0a920 100644 --- a/include/mgcp/mgcp.h +++ b/include/mgcp/mgcp.h @@ -29,6 +29,7 @@ #include #define RTP_PORT_DEFAULT 4000 + /** * Calculate the RTP audio port for the given multiplex * and the direction. This allows a semi static endpoint @@ -79,14 +80,13 @@ typedef int (*mgcp_policy)(struct mgcp_config *cfg, int endpoint, int state, con typedef int (*mgcp_reset)(struct mgcp_config *cfg); struct mgcp_config { - /* common configuration */ int source_port; char *local_ip; char *source_addr; + unsigned int number_endpoints; char *bts_ip; char *call_agent_addr; - /* default endpoint data */ struct in_addr bts_in; char *audio_name; int audio_payload; @@ -95,24 +95,19 @@ struct mgcp_config { int rtp_base_port; int endp_dscp; - /* only used in forward mode */ char *forward_ip; int forward_port; - unsigned int last_call_id; - - /* endpoint configuration */ - unsigned int number_endpoints; - struct mgcp_endpoint *endpoints; - /* spec handling */ int force_realloc; - /* callback functionality */ mgcp_change change_cb; mgcp_policy policy_cb; mgcp_reset reset_cb; void *data; + + struct mgcp_endpoint *endpoints; + unsigned int last_call_id; }; /* config management */ diff --git a/include/mgcp/mgcp_internal.h b/include/mgcp/mgcp_internal.h index ab6217d..2d9629a 100644 --- a/include/mgcp/mgcp_internal.h +++ b/include/mgcp/mgcp_internal.h @@ -33,6 +33,20 @@ enum mgcp_connection_mode { MGCP_CONN_RECV_ONLY = 1, MGCP_CONN_SEND_ONLY = 2, MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY, + MGCP_CONN_LOOPBACK = 4, +}; + +struct mgcp_rtp_state { + int initialized; + int patch; + + uint32_t orig_ssrc; + uint32_t ssrc; + uint16_t seq_no; + int lost_no; + int seq_offset; + uint32_t last_timestamp; + int32_t timestamp_offset; }; struct mgcp_endpoint { @@ -40,6 +54,7 @@ struct mgcp_endpoint { char *callid; char *local_options; int conn_mode; + int orig_mode; int bts_payload_type; int net_payload_type; @@ -68,6 +83,10 @@ struct mgcp_endpoint { /* statistics */ unsigned int in_bts; unsigned int in_remote; + + /* sequence bits */ + struct mgcp_rtp_state net_state; + struct mgcp_rtp_state bts_state; }; #define ENDPOINT_NUMBER(endp) abs(endp - endp->cfg->endpoints) diff --git a/src/mgcp/mgcp_network.c b/src/mgcp/mgcp_network.c index 0c86de5..c59b738 100644 --- a/src/mgcp/mgcp_network.c +++ b/src/mgcp/mgcp_network.c @@ -96,17 +96,53 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp) endp->net_rtp, buf, 1); } -static void patch_payload(int payload, char *data, int len) +static void patch_and_count(struct mgcp_rtp_state *state, int payload, char *data, int len) { + uint16_t seq; + uint32_t timestamp; struct rtp_hdr *rtp_hdr; if (len < sizeof(*rtp_hdr)) return; + rtp_hdr = (struct rtp_hdr *) data; + seq = ntohs(rtp_hdr->sequence); + timestamp = ntohl(rtp_hdr->timestamp); + + if (!state->initialized) { + state->seq_no = seq - 1; + state->ssrc = state->orig_ssrc = rtp_hdr->ssrc; + state->initialized = 1; + state->last_timestamp = timestamp; + } else if (state->ssrc != rtp_hdr->ssrc) { + state->ssrc = rtp_hdr->ssrc; + state->seq_offset = (state->seq_no + 1) - seq; + state->timestamp_offset = state->last_timestamp - timestamp; + state->patch = 1; + LOGP(DMGCP, LOGL_NOTICE, "The SSRC changed... SSRC: %u offset: %d\n", + state->ssrc, state->seq_offset); + } + + /* apply the offset and store it back to the packet */ + if (state->patch) { + seq += state->seq_offset; + rtp_hdr->sequence = htons(seq); + rtp_hdr->ssrc = state->orig_ssrc; + + timestamp += state->timestamp_offset; + rtp_hdr->timestamp = htonl(timestamp); + } + + /* seq changed, now compare if we have lost something */ + if (state->seq_no + 1u != seq) + state->lost_no = abs(seq - (state->seq_no + 1)); + state->seq_no = seq; + + state->last_timestamp = timestamp; + if (payload < 0) return; - rtp_hdr = (struct rtp_hdr *) data; rtp_hdr->payload_type = payload; } @@ -141,10 +177,8 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) } /* do not forward aynthing... maybe there is a packet from the bts */ - if (endp->ci == CI_UNUSED) { - LOGP(DMGCP, LOGL_DEBUG, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp)); + if (endp->ci == CI_UNUSED) return -1; - } /* * Figure out where to forward it to. This code assumes that we @@ -155,7 +189,7 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) */ #warning "Slight spec violation. With connection mode recvonly we should attempt to forward." dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 && - (endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port) + (endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port) ? DEST_BTS : DEST_NETWORK; proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP; @@ -196,15 +230,21 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) if (cfg->audio_loop) dest = !dest; + /* Loop based on the conn_mode, maybe undoing the above */ + if (endp->conn_mode == MGCP_CONN_LOOPBACK) + dest = !dest; + if (dest == DEST_NETWORK) { if (proto == PROTO_RTP) - patch_payload(endp->net_payload_type, buf, rc); + patch_and_count(&endp->bts_state, + endp->net_payload_type, buf, rc); return udp_send(fd->fd, &endp->remote, proto == PROTO_RTP ? endp->net_rtp : endp->net_rtcp, buf, rc); } else { if (proto == PROTO_RTP) - patch_payload(endp->bts_payload_type, buf, rc); + patch_and_count(&endp->net_state, + endp->bts_payload_type, buf, rc); return udp_send(fd->fd, &endp->bts, proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp, buf, rc); diff --git a/src/mgcp/mgcp_protocol.c b/src/mgcp/mgcp_protocol.c index 618503e..8b4923f 100644 --- a/src/mgcp/mgcp_protocol.c +++ b/src/mgcp/mgcp_protocol.c @@ -360,6 +360,8 @@ static int parse_conn_mode(const char* msg, int *conn_mode) *conn_mode = MGCP_CONN_RECV_ONLY; else if (strcmp(msg, "sendrecv") == 0) *conn_mode = MGCP_CONN_RECV_SEND; + else if (strcmp(msg, "loopback") == 0) + *conn_mode = MGCP_CONN_LOOPBACK; else { LOGP(DMGCP, LOGL_ERROR, "Unknown connection mode: '%s'\n", msg); ret = -1; @@ -385,6 +387,7 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg) if (cfg->force_realloc) { LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n", ENDPOINT_NUMBER(endp)); + mgcp_free_endp(endp); } else { LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n", ENDPOINT_NUMBER(endp)); @@ -409,6 +412,8 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg) error_code = 517; goto error2; } + + endp->orig_mode = endp->conn_mode; break; default: LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n", @@ -513,6 +518,7 @@ static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg) error_code = 517; goto error3; } + endp->orig_mode = endp->conn_mode; break; case 'Z': silent = strcmp("noanswer", (const char *)&msg->l3h[line_start + 3]) == 0; @@ -737,7 +743,7 @@ int mgcp_endpoints_allocate(struct mgcp_config *cfg) void mgcp_free_endp(struct mgcp_endpoint *endp) { LOGP(DMGCP, LOGL_DEBUG, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp)); - endp->ci= CI_UNUSED; + endp->ci = CI_UNUSED; if (endp->callid) { talloc_free(endp->callid); @@ -759,4 +765,9 @@ void mgcp_free_endp(struct mgcp_endpoint *endp) endp->in_bts = endp->in_remote = 0; memset(&endp->remote, 0, sizeof(endp->remote)); memset(&endp->bts, 0, sizeof(endp->bts)); + + memset(&endp->net_state, 0, sizeof(endp->net_state)); + memset(&endp->bts_state, 0, sizeof(endp->bts_state)); + + endp->conn_mode = endp->orig_mode = MGCP_CONN_NONE; } -- cgit v1.2.3