From 3713f78ac23ca815c361fe79378ff6d2e522ef6a Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 1 Sep 2014 11:02:05 +0200 Subject: [PATCH 1/5] mgcp: Use the rtp_hdr structure and extract ts/seq from there Use the rtp_hdr structure. The basic alignment issue remains and I need to merge/cherry-pick Jacob's getters for the ts, sequence number and other attributes. --- openbsc/include/openbsc/rtp.h | 1 + openbsc/src/libmgcp/mgcp_transcode.c | 14 ++++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/openbsc/include/openbsc/rtp.h b/openbsc/include/openbsc/rtp.h index 451d0defa..718fa84e6 100644 --- a/openbsc/include/openbsc/rtp.h +++ b/openbsc/include/openbsc/rtp.h @@ -35,4 +35,5 @@ struct rtp_hdr { uint16_t sequence; uint32_t timestamp; uint32_t ssrc; + uint8_t data[0]; } __attribute__((packed)); diff --git a/openbsc/src/libmgcp/mgcp_transcode.c b/openbsc/src/libmgcp/mgcp_transcode.c index 4d4cec8a2..88de7d2b2 100644 --- a/openbsc/src/libmgcp/mgcp_transcode.c +++ b/openbsc/src/libmgcp/mgcp_transcode.c @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -396,8 +397,9 @@ int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, char *data, int *len, int buf_size) { struct mgcp_process_rtp_state *state = dst_end->rtp_process_data; - size_t rtp_hdr_size = 12; - char *payload_data = data + rtp_hdr_size; + const size_t rtp_hdr_size = sizeof(struct rtp_hdr); + struct rtp_hdr *rtp_hdr = (struct rtp_hdr *) data; + char *payload_data = (char *) &rtp_hdr->data[0]; int payload_len = *len - rtp_hdr_size; uint8_t *src = (uint8_t *)payload_data; uint8_t *dst = (uint8_t *)payload_data; @@ -427,9 +429,9 @@ int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, /* TODO: check payload type (-> G.711 comfort noise) */ if (payload_len > 0) { - ts_no = ntohl(*(uint32_t*)(data+4)); + ts_no = ntohl(rtp_hdr->timestamp); if (!state->is_running) { - state->next_seq = ntohs(*(uint16_t*)(data+2)); + state->next_seq = ntohs(rtp_hdr->sequence); state->next_time = ts_no; state->is_running = 1; } @@ -504,8 +506,8 @@ int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, nsamples -= state->sample_cnt; *len = rtp_hdr_size + rc; - *(uint16_t*)(data+2) = htons(state->next_seq); - *(uint32_t*)(data+4) = htonl(ts_no); + rtp_hdr->sequence = htons(state->next_seq); + rtp_hdr->timestamp = htonl(ts_no); state->next_seq += 1; state->next_time = ts_no + nsamples; From cac2438b0c33f54a6dcac55b55e8cfc33de197b2 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 1 Sep 2014 10:35:55 +0200 Subject: [PATCH 2/5] mgcp: Move the "codec" params to a struct We might be offered multiple codecs by the remote and need to switch between them once we receive data. Do this by moving it to a struct so we can separate between proposed and current codec. In SDP we can have multiple codecs but a global ptime. The current code doesn't separate that clearly instead we write it to the main codec. --- openbsc/contrib/testconv/testconv_main.c | 10 +-- openbsc/include/openbsc/mgcp_internal.h | 21 ++++-- openbsc/src/libmgcp/mgcp_network.c | 12 ++-- openbsc/src/libmgcp/mgcp_protocol.c | 78 +++++++++++----------- openbsc/src/libmgcp/mgcp_transcode.c | 51 +++++++------- openbsc/src/libmgcp/mgcp_vty.c | 8 ++- openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c | 4 +- openbsc/tests/mgcp/mgcp_test.c | 14 ++-- openbsc/tests/mgcp/mgcp_transcoding_test.c | 10 +-- 9 files changed, 111 insertions(+), 97 deletions(-) diff --git a/openbsc/contrib/testconv/testconv_main.c b/openbsc/contrib/testconv/testconv_main.c index 773be26a3..6c95c5542 100644 --- a/openbsc/contrib/testconv/testconv_main.c +++ b/openbsc/contrib/testconv/testconv_main.c @@ -64,16 +64,16 @@ int main(int argc, char **argv) if (argc <= 2) errx(1, "Usage: {gsm|g729|pcma|l16} {gsm|g729|pcma|l16} [SPP]"); - if ((src_end->payload_type = audio_name_to_type(argv[1])) == -1) + if ((src_end->codec.payload_type = audio_name_to_type(argv[1])) == -1) errx(1, "invalid input format '%s'", argv[1]); - if ((dst_end->payload_type = audio_name_to_type(argv[2])) == -1) + if ((dst_end->codec.payload_type = audio_name_to_type(argv[2])) == -1) errx(1, "invalid output format '%s'", argv[2]); if (argc > 3) out_samples = atoi(argv[3]); if (out_samples) { - dst_end->frame_duration_den = dst_end->rate; - dst_end->frame_duration_num = out_samples; + dst_end->codec.frame_duration_den = dst_end->codec.rate; + dst_end->codec.frame_duration_num = out_samples; dst_end->frames_per_packet = 1; } @@ -87,7 +87,7 @@ int main(int argc, char **argv) in_size = mgcp_transcoding_get_frame_size(state, in_samples, 0); OSMO_ASSERT(sizeof(buf) >= in_size + 12); - buf[1] = src_end->payload_type; + buf[1] = src_end->codec.payload_type; *(uint16_t*)(buf+2) = htons(1); *(uint32_t*)(buf+4) = htonl(0); *(uint32_t*)(buf+8) = htonl(0xaabbccdd); diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index 3d308835e..245890994 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -67,6 +67,17 @@ struct mgcp_rtp_state { struct mgcp_rtp_stream_state out_stream; }; +struct mgcp_rtp_codec { + uint32_t rate; + int channels; + uint32_t frame_duration_num; + uint32_t frame_duration_den; + + int payload_type; + char *audio_name; + char *subtype_name; +}; + struct mgcp_rtp_end { /* statistics */ unsigned int packets; @@ -77,17 +88,13 @@ struct mgcp_rtp_end { /* in network byte order */ int rtp_port, rtcp_port; + /* audio codec information */ + struct mgcp_rtp_codec codec; + /* per endpoint data */ - int payload_type; - uint32_t rate; - int channels; - uint32_t frame_duration_num; - uint32_t frame_duration_den; int frames_per_packet; uint32_t packet_duration_ms; char *fmtp_extra; - char *audio_name; - char *subtype_name; int output_enabled; int force_output_ptime; diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c index 7dcf3f3ae..587d4e88c 100644 --- a/openbsc/src/libmgcp/mgcp_network.c +++ b/openbsc/src/libmgcp/mgcp_network.c @@ -239,7 +239,7 @@ static int adjust_rtp_timestamp_offset(struct mgcp_endpoint *endp, inet_ntoa(addr->sin_addr), ntohs(addr->sin_port), endp->conn_mode); } else { - tsdelta = rtp_end->rate * 20 / 1000; + tsdelta = rtp_end->codec.rate * 20 / 1000; LOGP(DMGCP, LOGL_NOTICE, "Fixed packet duration and last timestamp delta " "are not available on 0x%x, " @@ -326,8 +326,8 @@ void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp, /* Use the BTS side parameters when passing the SDP data (for * downlink) to the net peer. */ - *payload_type = endp->bts_end.payload_type; - *audio_name = endp->bts_end.audio_name; + *payload_type = endp->bts_end.codec.payload_type; + *audio_name = endp->bts_end.codec.audio_name; *fmtp_extra = endp->bts_end.fmtp_extra; } @@ -348,7 +348,7 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta uint16_t seq, udelta; uint32_t timestamp, ssrc; struct rtp_hdr *rtp_hdr; - int payload = rtp_end->payload_type; + int payload = rtp_end->codec.payload_type; if (len < sizeof(*rtp_hdr)) return; @@ -356,7 +356,7 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta rtp_hdr = (struct rtp_hdr *) data; seq = ntohs(rtp_hdr->sequence); timestamp = ntohl(rtp_hdr->timestamp); - arrival_time = get_current_ts(rtp_end->rate); + arrival_time = get_current_ts(rtp_end->codec.rate); ssrc = ntohl(rtp_hdr->ssrc); transit = arrival_time - timestamp; @@ -380,7 +380,7 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta inet_ntoa(addr->sin_addr), ntohs(addr->sin_port), endp->conn_mode); if (state->packet_duration == 0) { - state->packet_duration = rtp_end->rate * 20 / 1000; + state->packet_duration = rtp_end->codec.rate * 20 / 1000; LOGP(DMGCP, LOGL_NOTICE, "Fixed packet duration is not available on 0x%x, " "using fixed 20ms instead: %d from %s:%d in %d\n", diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index ae275a890..d2a9f093e 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -598,20 +598,20 @@ static int parse_conn_mode(const char *msg, struct mgcp_endpoint *endp) return ret; } -static int set_audio_info(void *ctx, struct mgcp_rtp_end *rtp, +static int set_audio_info(void *ctx, struct mgcp_rtp_codec *codec, int payload_type, const char *audio_name) { - int rate = rtp->rate; - int channels = rtp->channels; + int rate = codec->rate; + int channels = codec->channels; char audio_codec[64]; - talloc_free(rtp->subtype_name); - rtp->subtype_name = NULL; - talloc_free(rtp->audio_name); - rtp->audio_name = NULL; + talloc_free(codec->subtype_name); + codec->subtype_name = NULL; + talloc_free(codec->audio_name); + codec->audio_name = NULL; if (payload_type != PTYPE_UNDEFINED) - rtp->payload_type = payload_type; + codec->payload_type = payload_type; if (!audio_name) { switch (payload_type) { @@ -630,17 +630,17 @@ static int set_audio_info(void *ctx, struct mgcp_rtp_end *rtp, audio_codec, &rate, &channels) < 1) return -EINVAL; - rtp->rate = rate; - rtp->channels = channels; - rtp->subtype_name = talloc_strdup(ctx, audio_codec); - rtp->audio_name = talloc_strdup(ctx, audio_name); + codec->rate = rate; + codec->channels = channels; + codec->subtype_name = talloc_strdup(ctx, audio_codec); + codec->audio_name = talloc_strdup(ctx, audio_name); if (!strcmp(audio_codec, "G729")) { - rtp->frame_duration_num = 10; - rtp->frame_duration_den = 1000; + codec->frame_duration_num = 10; + codec->frame_duration_den = 1000; } else { - rtp->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM; - rtp->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN; + codec->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM; + codec->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN; } if (payload_type < 0) { @@ -654,7 +654,7 @@ static int set_audio_info(void *ctx, struct mgcp_rtp_end *rtp, payload_type = 18; } - rtp->payload_type = payload_type; + codec->payload_type = payload_type; } if (channels != 1) @@ -761,7 +761,7 @@ static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p) if (payload != audio_payload) break; - set_audio_info(p->cfg, rtp, payload, audio_name); + set_audio_info(p->cfg, &rtp->codec, payload, audio_name); } else if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) { if (ptime2 > 0 && ptime2 != ptime) @@ -769,8 +769,8 @@ static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p) else rtp->packet_duration_ms = ptime; } else if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) { - if (ptime2 * rtp->frame_duration_den > - rtp->frame_duration_num * 1500) + if (ptime2 * rtp->codec.frame_duration_den > + rtp->codec.frame_duration_num * 1500) /* more than 1 frame */ rtp->packet_duration_ms = 0; } @@ -785,7 +785,7 @@ static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p) rtp->rtp_port = htons(port); rtp->rtcp_port = htons(port + 1); found_media = 1; - set_audio_info(p->cfg, rtp, audio_payload, NULL); + set_audio_info(p->cfg, &rtp->codec, audio_payload, NULL); } break; } @@ -814,8 +814,8 @@ static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p) LOGP(DMGCP, LOGL_NOTICE, "Got media info via SDP: port %d, payload %d (%s), " "duration %d, addr %s\n", - ntohs(rtp->rtp_port), rtp->payload_type, - rtp->subtype_name ? rtp->subtype_name : "unknown", + ntohs(rtp->rtp_port), rtp->codec.payload_type, + rtp->codec.subtype_name ? rtp->codec.subtype_name : "unknown", rtp->packet_duration_ms, inet_ntoa(rtp->addr)); return found_media; @@ -872,13 +872,13 @@ uint32_t mgcp_rtp_packet_duration(struct mgcp_endpoint *endp, /* Get the number of frames per channel and packet */ if (rtp->frames_per_packet) f = rtp->frames_per_packet; - else if (rtp->packet_duration_ms && rtp->frame_duration_num) { - int den = 1000 * rtp->frame_duration_num; - f = (rtp->packet_duration_ms * rtp->frame_duration_den + den/2) + else if (rtp->packet_duration_ms && rtp->codec.frame_duration_num) { + int den = 1000 * rtp->codec.frame_duration_num; + f = (rtp->packet_duration_ms * rtp->codec.frame_duration_den + den/2) / den; } - return rtp->rate * f * rtp->frame_duration_num / rtp->frame_duration_den; + return rtp->codec.rate * f * rtp->codec.frame_duration_num / rtp->codec.frame_duration_den; } static int mgcp_parse_osmux_cid(const char *line) @@ -1025,13 +1025,13 @@ mgcp_header_done: endp->allocated = 1; /* set up RTP media parameters */ - set_audio_info(p->cfg, &endp->bts_end, tcfg->audio_payload, tcfg->audio_name); + set_audio_info(p->cfg, &endp->bts_end.codec, tcfg->audio_payload, tcfg->audio_name); endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints, tcfg->audio_fmtp_extra); if (have_sdp) parse_sdp_data(&endp->net_end, p); else if (endp->local_options.codec) - set_audio_info(p->cfg, &endp->net_end, + set_audio_info(p->cfg, &endp->net_end.codec, PTYPE_UNDEFINED, endp->local_options.codec); if (p->cfg->bts_force_ptime) { @@ -1147,7 +1147,7 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p) local_options); if (!have_sdp && endp->local_options.codec) - set_audio_info(p->cfg, &endp->net_end, + set_audio_info(p->cfg, &endp->net_end.codec, PTYPE_UNDEFINED, endp->local_options.codec); setup_rtp_processing(endp); @@ -1461,24 +1461,24 @@ static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end) end->dropped_packets = 0; memset(&end->addr, 0, sizeof(end->addr)); end->rtp_port = end->rtcp_port = 0; - end->payload_type = -1; + end->codec.payload_type = -1; end->local_alloc = -1; talloc_free(end->fmtp_extra); end->fmtp_extra = NULL; - talloc_free(end->subtype_name); - end->subtype_name = NULL; - talloc_free(end->audio_name); - end->audio_name = NULL; + talloc_free(end->codec.subtype_name); + end->codec.subtype_name = NULL; + talloc_free(end->codec.audio_name); + end->codec.audio_name = NULL; talloc_free(end->rtp_process_data); end->rtp_process_data = NULL; /* Set default values */ - end->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM; - end->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN; + end->codec.frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM; + end->codec.frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN; end->frames_per_packet = 0; /* unknown */ end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS; - end->rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE; - end->channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS; + end->codec.rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE; + end->codec.channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS; end->output_enabled = 0; } diff --git a/openbsc/src/libmgcp/mgcp_transcode.c b/openbsc/src/libmgcp/mgcp_transcode.c index 88de7d2b2..e961ba6cc 100644 --- a/openbsc/src/libmgcp/mgcp_transcode.c +++ b/openbsc/src/libmgcp/mgcp_transcode.c @@ -45,22 +45,22 @@ int mgcp_transcoding_get_frame_size(void *state_, int nsamples, int dst) 1) * state->src_frame_size; } -static enum audio_format get_audio_format(const struct mgcp_rtp_end *rtp_end) +static enum audio_format get_audio_format(const struct mgcp_rtp_codec *codec) { - if (rtp_end->subtype_name) { - if (!strcmp("GSM", rtp_end->subtype_name)) + if (codec->subtype_name) { + if (!strcmp("GSM", codec->subtype_name)) return AF_GSM; - if (!strcmp("PCMA", rtp_end->subtype_name)) + if (!strcmp("PCMA", codec->subtype_name)) return AF_PCMA; #ifdef HAVE_BCG729 - if (!strcmp("G729", rtp_end->subtype_name)) + if (!strcmp("G729", codec->subtype_name)) return AF_G729; #endif - if (!strcmp("L16", rtp_end->subtype_name)) + if (!strcmp("L16", codec->subtype_name)) return AF_L16; } - switch (rtp_end->payload_type) { + switch (codec->payload_type) { case 3 /* GSM */: return AF_GSM; case 8 /* PCMA */: @@ -141,6 +141,8 @@ int mgcp_transcoding_setup(struct mgcp_endpoint *endp, { struct mgcp_process_rtp_state *state; enum audio_format src_fmt, dst_fmt; + const struct mgcp_rtp_codec *src_codec = &src_end->codec; + const struct mgcp_rtp_codec *dst_codec = &dst_end->codec; /* cleanup first */ if (dst_end->rtp_process_data) { @@ -151,34 +153,34 @@ int mgcp_transcoding_setup(struct mgcp_endpoint *endp, if (!src_end) return 0; - src_fmt = get_audio_format(src_end); - dst_fmt = get_audio_format(dst_end); + src_fmt = get_audio_format(src_codec); + dst_fmt = get_audio_format(dst_codec); LOGP(DMGCP, LOGL_ERROR, "Checking transcoding: %s (%d) -> %s (%d)\n", - src_end->subtype_name, src_end->payload_type, - dst_end->subtype_name, dst_end->payload_type); + src_codec->subtype_name, src_codec->payload_type, + dst_codec->subtype_name, dst_codec->payload_type); if (src_fmt == AF_INVALID || dst_fmt == AF_INVALID) { - if (!src_end->subtype_name || !dst_end->subtype_name) + if (!src_codec->subtype_name || !dst_codec->subtype_name) /* Not enough info, do nothing */ return 0; - if (strcmp(src_end->subtype_name, dst_end->subtype_name) == 0) + if (strcmp(src_codec->subtype_name, dst_codec->subtype_name) == 0) /* Nothing to do */ return 0; LOGP(DMGCP, LOGL_ERROR, "Cannot transcode: %s codec not supported (%s -> %s).\n", src_fmt != AF_INVALID ? "destination" : "source", - src_end->audio_name, dst_end->audio_name); + src_codec->audio_name, dst_codec->audio_name); return -EINVAL; } - if (src_end->rate && dst_end->rate && src_end->rate != dst_end->rate) { + if (src_codec->rate && dst_codec->rate && src_codec->rate != dst_codec->rate) { LOGP(DMGCP, LOGL_ERROR, "Cannot transcode: rate conversion (%d -> %d) not supported.\n", - src_end->rate, dst_end->rate); + src_codec->rate, dst_codec->rate); return -EINVAL; } @@ -269,8 +271,8 @@ int mgcp_transcoding_setup(struct mgcp_endpoint *endp, "Initialized RTP processing on: 0x%x " "conv: %d (%d, %d, %s) -> %d (%d, %d, %s)\n", ENDPOINT_NUMBER(endp), - src_fmt, src_end->payload_type, src_end->rate, src_end->fmtp_extra, - dst_fmt, dst_end->payload_type, dst_end->rate, dst_end->fmtp_extra); + src_fmt, src_codec->payload_type, src_codec->rate, src_end->fmtp_extra, + dst_fmt, dst_codec->payload_type, dst_codec->rate, dst_end->fmtp_extra); return 0; } @@ -281,16 +283,19 @@ void mgcp_transcoding_net_downlink_format(struct mgcp_endpoint *endp, const char**fmtp_extra) { struct mgcp_process_rtp_state *state = endp->net_end.rtp_process_data; - if (!state || endp->net_end.payload_type < 0) { - *payload_type = endp->bts_end.payload_type; - *audio_name = endp->bts_end.audio_name; + struct mgcp_rtp_codec *net_codec = &endp->net_end.codec; + struct mgcp_rtp_codec *bts_codec = &endp->bts_end.codec; + + if (!state || net_codec->payload_type < 0) { + *payload_type = bts_codec->payload_type; + *audio_name = bts_codec->audio_name; *fmtp_extra = endp->bts_end.fmtp_extra; return; } - *payload_type = endp->net_end.payload_type; + *payload_type = net_codec->payload_type; + *audio_name = net_codec->audio_name; *fmtp_extra = endp->net_end.fmtp_extra; - *audio_name = endp->net_end.audio_name; } static int decode_audio(struct mgcp_process_rtp_state *state, diff --git a/openbsc/src/libmgcp/mgcp_vty.c b/openbsc/src/libmgcp/mgcp_vty.c index 9ae0bc9fa..b29eb6b4d 100644 --- a/openbsc/src/libmgcp/mgcp_vty.c +++ b/openbsc/src/libmgcp/mgcp_vty.c @@ -147,6 +147,8 @@ static int config_write_mgcp(struct vty *vty) static void dump_rtp_end(const char *end_name, struct vty *vty, struct mgcp_rtp_state *state, struct mgcp_rtp_end *end) { + struct mgcp_rtp_codec *codec = &end->codec; + vty_out(vty, " %s%s" " Timestamp Errs: %d->%d%s" @@ -160,10 +162,10 @@ static void dump_rtp_end(const char *end_name, struct vty *vty, state->in_stream.err_ts_counter, state->out_stream.err_ts_counter, VTY_NEWLINE, end->dropped_packets, VTY_NEWLINE, - end->payload_type, end->rate, end->channels, VTY_NEWLINE, - end->frame_duration_num, end->frame_duration_den, VTY_NEWLINE, + codec->payload_type, codec->rate, codec->channels, VTY_NEWLINE, + codec->frame_duration_num, codec->frame_duration_den, VTY_NEWLINE, end->frames_per_packet, end->packet_duration_ms, VTY_NEWLINE, - end->fmtp_extra, end->audio_name, end->subtype_name, VTY_NEWLINE, + end->fmtp_extra, codec->audio_name, codec->subtype_name, VTY_NEWLINE, end->output_enabled, end->force_output_ptime, VTY_NEWLINE); } diff --git a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c index d58039788..97593031c 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c +++ b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c @@ -552,7 +552,7 @@ static int bsc_mgcp_policy_cb(struct mgcp_trunk_config *tcfg, int endpoint, int bsc_msg = bsc_mgcp_rewrite((char *) nat->mgcp_msg, nat->mgcp_length, sccp->bsc_endp, nat->mgcp_cfg->source_addr, mgcp_endp->bts_end.local_port, osmux_cid, - &mgcp_endp->net_end.payload_type); + &mgcp_endp->net_end.codec.payload_type); if (!bsc_msg) { LOGP(DMGCP, LOGL_ERROR, "Failed to patch the msg.\n"); return MGCP_POLICY_CONT; @@ -746,7 +746,7 @@ void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg) output = bsc_mgcp_rewrite((char * ) msg->l2h, msgb_l2len(msg), -1, bsc->nat->mgcp_cfg->source_addr, endp->net_end.local_port, -1, - &endp->bts_end.payload_type); + &endp->bts_end.codec.payload_type); if (!output) { LOGP(DMGCP, LOGL_ERROR, "Failed to rewrite MGCP msg.\n"); return; diff --git a/openbsc/tests/mgcp/mgcp_test.c b/openbsc/tests/mgcp/mgcp_test.c index 50c8b2d0a..06981dd44 100644 --- a/openbsc/tests/mgcp/mgcp_test.c +++ b/openbsc/tests/mgcp/mgcp_test.c @@ -410,7 +410,7 @@ static void test_messages(void) /* reset endpoints */ for (i = 0; i < cfg->trunk.number_endpoints; i++) { endp = &cfg->trunk.endpoints[i]; - endp->net_end.payload_type = PTYPE_NONE; + endp->net_end.codec.payload_type = PTYPE_NONE; endp->net_end.packet_duration_ms = -1; OSMO_ASSERT(endp->conn_mode == MGCP_CONN_NONE); @@ -498,18 +498,18 @@ static void test_messages(void) fprintf(stderr, "endpoint %d: " "payload type BTS %d (exp %d), NET %d (exp %d)\n", last_endpoint, - endp->bts_end.payload_type, t->exp_bts_ptype, - endp->net_end.payload_type, t->exp_net_ptype); + endp->bts_end.codec.payload_type, t->exp_bts_ptype, + endp->net_end.codec.payload_type, t->exp_net_ptype); if (t->exp_bts_ptype != PTYPE_IGNORE) - OSMO_ASSERT(endp->bts_end.payload_type == + OSMO_ASSERT(endp->bts_end.codec.payload_type == t->exp_bts_ptype); if (t->exp_net_ptype != PTYPE_IGNORE) - OSMO_ASSERT(endp->net_end.payload_type == + OSMO_ASSERT(endp->net_end.codec.payload_type == t->exp_net_ptype); /* Reset them again for next test */ - endp->net_end.payload_type = PTYPE_NONE; + endp->net_end.codec.payload_type = PTYPE_NONE; } } @@ -830,7 +830,7 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts) mgcp_initialize_endp(&endp); - rtp->payload_type = 98; + rtp->codec.payload_type = 98; for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) { struct rtp_packet_info *info = test_rtp_packets1 + i; diff --git a/openbsc/tests/mgcp/mgcp_transcoding_test.c b/openbsc/tests/mgcp/mgcp_transcoding_test.c index 44f307251..079f62eba 100644 --- a/openbsc/tests/mgcp/mgcp_transcoding_test.c +++ b/openbsc/tests/mgcp/mgcp_transcoding_test.c @@ -183,14 +183,14 @@ static int given_configured_endpoint(int in_samples, int out_samples, mgcp_initialize_endp(endp); dst_end = &endp->bts_end; - dst_end->payload_type = audio_name_to_type(dstfmt); + dst_end->codec.payload_type = audio_name_to_type(dstfmt); src_end = &endp->net_end; - src_end->payload_type = audio_name_to_type(srcfmt); + src_end->codec.payload_type = audio_name_to_type(srcfmt); if (out_samples) { - dst_end->frame_duration_den = dst_end->rate; - dst_end->frame_duration_num = out_samples; + dst_end->codec.frame_duration_den = dst_end->codec.rate; + dst_end->codec.frame_duration_num = out_samples; dst_end->frames_per_packet = 1; dst_end->force_output_ptime = 1; } @@ -463,7 +463,7 @@ static int test_repacking(int in_samples, int out_samples, int no_transcode) out_size = mgcp_transcoding_get_frame_size(state, -1, 1); OSMO_ASSERT(sizeof(buf) >= out_size + 12); - buf[1] = endp->net_end.payload_type; + buf[1] = endp->net_end.codec.payload_type; *(uint16_t*)(buf+2) = htons(1); *(uint32_t*)(buf+4) = htonl(0); *(uint32_t*)(buf+8) = htonl(0xaabbccdd); From fa80d07de0975fe3b00daeadd5d9f685abf62653 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 1 Sep 2014 10:40:19 +0200 Subject: [PATCH 3/5] mgcp: Group codec reset and put it to a separate method. --- openbsc/src/libmgcp/mgcp_protocol.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index d2a9f093e..fff2ece5c 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -1449,6 +1449,19 @@ struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index) return NULL; } +static void mgcp_rtp_codec_reset(struct mgcp_rtp_codec *codec) +{ + codec->payload_type = -1; + talloc_free(codec->subtype_name); + codec->subtype_name = NULL; + talloc_free(codec->audio_name); + codec->audio_name = NULL; + codec->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM; + codec->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN; + codec->rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE; + codec->channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS; +} + static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end) { if (end->local_alloc == PORT_ALLOC_DYNAMIC) { @@ -1461,25 +1474,18 @@ static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end) end->dropped_packets = 0; memset(&end->addr, 0, sizeof(end->addr)); end->rtp_port = end->rtcp_port = 0; - end->codec.payload_type = -1; end->local_alloc = -1; talloc_free(end->fmtp_extra); end->fmtp_extra = NULL; - talloc_free(end->codec.subtype_name); - end->codec.subtype_name = NULL; - talloc_free(end->codec.audio_name); - end->codec.audio_name = NULL; talloc_free(end->rtp_process_data); end->rtp_process_data = NULL; /* Set default values */ - end->codec.frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM; - end->codec.frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN; end->frames_per_packet = 0; /* unknown */ end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS; - end->codec.rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE; - end->codec.channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS; end->output_enabled = 0; + + mgcp_rtp_codec_reset(&end->codec); } static void mgcp_rtp_end_init(struct mgcp_rtp_end *end) From e46bc2714d3703ce11d71edcc3a0f060ff513ce3 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 1 Sep 2014 10:50:22 +0200 Subject: [PATCH 4/5] mgcp: Store one more codec/payload type if it is present In case of some RTP proxy from time to time we are offered both G729 and G711 but only one of them will work. I intend to adjust the codec at runtime in case we receive the wrong codec. --- openbsc/include/openbsc/mgcp_internal.h | 1 + openbsc/src/libmgcp/mgcp_protocol.c | 25 +++-- openbsc/tests/mgcp/mgcp_test.c | 126 +++++++++++++++++++++++- openbsc/tests/mgcp/mgcp_test.ok | 1 + 4 files changed, 144 insertions(+), 9 deletions(-) diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index 245890994..34c3d973a 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -90,6 +90,7 @@ struct mgcp_rtp_end { /* audio codec information */ struct mgcp_rtp_codec codec; + struct mgcp_rtp_codec alt_codec; /* TODO/XXX: make it generic */ /* per endpoint data */ int frames_per_packet; diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index fff2ece5c..a728b67c4 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -738,7 +738,9 @@ static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p) { char *line; int found_media = 0; + /* TODO/XXX make it more generic */ int audio_payload = -1; + int audio_payload_alt = -1; for_each_line(line, p->save) { switch (line[0]) { @@ -758,10 +760,12 @@ static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p) if (sscanf(line, "a=rtpmap:%d %63s", &payload, audio_name) == 2) { - if (payload != audio_payload) - break; - - set_audio_info(p->cfg, &rtp->codec, payload, audio_name); + if (payload == audio_payload) + set_audio_info(p->cfg, &rtp->codec, + payload, audio_name); + else if (payload == audio_payload_alt) + set_audio_info(p->cfg, &rtp->alt_codec, + payload, audio_name); } else if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) { if (ptime2 > 0 && ptime2 != ptime) @@ -769,6 +773,7 @@ static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p) else rtp->packet_duration_ms = ptime; } else if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) { + /* TODO/XXX: Store this per codec and derive it on use */ if (ptime2 * rtp->codec.frame_duration_den > rtp->codec.frame_duration_num * 1500) /* more than 1 frame */ @@ -777,15 +782,20 @@ static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p) break; } case 'm': { - int port; + int port, rc; audio_payload = -1; + audio_payload_alt = -1; - if (sscanf(line, "m=audio %d RTP/AVP %d", - &port, &audio_payload) == 2) { + rc = sscanf(line, "m=audio %d RTP/AVP %d %d", + &port, &audio_payload, &audio_payload_alt); + if (rc >= 2) { rtp->rtp_port = htons(port); rtp->rtcp_port = htons(port + 1); found_media = 1; set_audio_info(p->cfg, &rtp->codec, audio_payload, NULL); + if (rc == 3) + set_audio_info(p->cfg, &rtp->alt_codec, + audio_payload_alt, NULL); } break; } @@ -1486,6 +1496,7 @@ static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end) end->output_enabled = 0; mgcp_rtp_codec_reset(&end->codec); + mgcp_rtp_codec_reset(&end->alt_codec); } static void mgcp_rtp_end_init(struct mgcp_rtp_end *end) diff --git a/openbsc/tests/mgcp/mgcp_test.c b/openbsc/tests/mgcp/mgcp_test.c index 06981dd44..a0575032c 100644 --- a/openbsc/tests/mgcp/mgcp_test.c +++ b/openbsc/tests/mgcp/mgcp_test.c @@ -1,6 +1,6 @@ /* - * (C) 2011-2012 by Holger Hans Peter Freyther - * (C) 2011-2012 by On-Waves + * (C) 2011-2012,2014 by Holger Hans Peter Freyther + * (C) 2011-2012,2014 by On-Waves * All Rights Reserved * * This program is free software; you can redistribute it and/or modify @@ -268,6 +268,61 @@ static void test_strline(void) #define PTYPE_NONE 128 #define PTYPE_NYI PTYPE_NONE +#define CRCX_MULT_1 "CRCX 2 1@mgw MGCP 1.0\r\n" \ + "M: recvonly\r\n" \ + "C: 2\r\n" \ + "X\r\n" \ + "L: p:20\r\n" \ + "\r\n" \ + "v=0\r\n" \ + "c=IN IP4 123.12.12.123\r\n" \ + "m=audio 5904 RTP/AVP 18 97\r\n"\ + "a=rtpmap:18 G729/8000\r\n" \ + "a=rtpmap:97 GSM-EFR/8000\r\n" \ + "a=ptime:40\r\n" + +#define CRCX_MULT_2 "CRCX 2 2@mgw MGCP 1.0\r\n" \ + "M: recvonly\r\n" \ + "C: 2\r\n" \ + "X\r\n" \ + "L: p:20\r\n" \ + "\r\n" \ + "v=0\r\n" \ + "c=IN IP4 123.12.12.123\r\n" \ + "m=audio 5904 RTP/AVP 18 97 101\r\n"\ + "a=rtpmap:18 G729/8000\r\n" \ + "a=rtpmap:97 GSM-EFR/8000\r\n" \ + "a=rtpmap:101 FOO/8000\r\n" \ + "a=ptime:40\r\n" + +#define CRCX_MULT_3 "CRCX 2 3@mgw MGCP 1.0\r\n" \ + "M: recvonly\r\n" \ + "C: 2\r\n" \ + "X\r\n" \ + "L: p:20\r\n" \ + "\r\n" \ + "v=0\r\n" \ + "c=IN IP4 123.12.12.123\r\n" \ + "m=audio 5904 RTP/AVP\r\n" \ + "a=rtpmap:18 G729/8000\r\n" \ + "a=rtpmap:97 GSM-EFR/8000\r\n" \ + "a=rtpmap:101 FOO/8000\r\n" \ + "a=ptime:40\r\n" + +#define CRCX_MULT_4 "CRCX 2 4@mgw MGCP 1.0\r\n" \ + "M: recvonly\r\n" \ + "C: 2\r\n" \ + "X\r\n" \ + "L: p:20\r\n" \ + "\r\n" \ + "v=0\r\n" \ + "c=IN IP4 123.12.12.123\r\n" \ + "m=audio 5904 RTP/AVP 18\r\n" \ + "a=rtpmap:18 G729/8000\r\n" \ + "a=rtpmap:97 GSM-EFR/8000\r\n" \ + "a=rtpmap:101 FOO/8000\r\n" \ + "a=ptime:40\r\n" + struct mgcp_test { const char *name; const char *req; @@ -877,6 +932,72 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts) force_monotonic_time_us = -1; } +static void test_multilple_codec(void) +{ + struct mgcp_config *cfg; + struct mgcp_endpoint *endp; + struct msgb *inp, *resp; + + printf("Testing multiple payload types\n"); + + cfg = mgcp_config_alloc(); + cfg->trunk.number_endpoints = 64; + mgcp_endpoints_allocate(&cfg->trunk); + cfg->policy_cb = mgcp_test_policy_cb; + mgcp_endpoints_allocate(mgcp_trunk_alloc(cfg, 1)); + + /* Allocate endpoint 1@mgw with two codecs */ + last_endpoint = -1; + inp = create_msg(CRCX_MULT_1); + resp = mgcp_handle_message(cfg, inp); + msgb_free(inp); + msgb_free(resp); + + OSMO_ASSERT(last_endpoint == 1); + endp = &cfg->trunk.endpoints[last_endpoint]; + OSMO_ASSERT(endp->net_end.codec.payload_type == 18); + OSMO_ASSERT(endp->net_end.alt_codec.payload_type == 97); + + /* Allocate 2@mgw with three codecs, last one ignored */ + last_endpoint = -1; + inp = create_msg(CRCX_MULT_2); + resp = mgcp_handle_message(cfg, inp); + msgb_free(inp); + msgb_free(resp); + + OSMO_ASSERT(last_endpoint == 2); + endp = &cfg->trunk.endpoints[last_endpoint]; + OSMO_ASSERT(endp->net_end.codec.payload_type == 18); + OSMO_ASSERT(endp->net_end.alt_codec.payload_type == 97); + + /* Allocate 3@mgw with no codecs, check for PT == -1 */ + last_endpoint = -1; + inp = create_msg(CRCX_MULT_3); + resp = mgcp_handle_message(cfg, inp); + msgb_free(inp); + msgb_free(resp); + + OSMO_ASSERT(last_endpoint == 3); + endp = &cfg->trunk.endpoints[last_endpoint]; + OSMO_ASSERT(endp->net_end.codec.payload_type == -1); + OSMO_ASSERT(endp->net_end.alt_codec.payload_type == -1); + + /* Allocate 4@mgw with a single codec */ + last_endpoint = -1; + inp = create_msg(CRCX_MULT_4); + resp = mgcp_handle_message(cfg, inp); + msgb_free(inp); + msgb_free(resp); + + OSMO_ASSERT(last_endpoint == 4); + endp = &cfg->trunk.endpoints[last_endpoint]; + OSMO_ASSERT(endp->net_end.codec.payload_type == 18); + OSMO_ASSERT(endp->net_end.alt_codec.payload_type == -1); + + + talloc_free(cfg); +} + int main(int argc, char **argv) { osmo_init_logging(&log_info); @@ -892,6 +1013,7 @@ int main(int argc, char **argv) test_packet_error_detection(0, 0); test_packet_error_detection(0, 1); test_packet_error_detection(1, 1); + test_multilple_codec(); printf("Done\n"); return EXIT_SUCCESS; diff --git a/openbsc/tests/mgcp/mgcp_test.ok b/openbsc/tests/mgcp/mgcp_test.ok index 033f783f3..a56a3fd1b 100644 --- a/openbsc/tests/mgcp/mgcp_test.ok +++ b/openbsc/tests/mgcp/mgcp_test.ok @@ -474,4 +474,5 @@ Stats: Jitter = 0, Transit = -144000 In TS: 160320, dTS: 160, Seq: 1002 Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0 Stats: Jitter = 0, Transit = -144000 +Testing multiple payload types Done From 4680121fe6deb14aca0d4b32c124eb49d224a48b Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 1 Sep 2014 22:20:57 +0200 Subject: [PATCH 5/5] mgcp: Deal with receiving another payload type In case we get offered G729 and G711 we might have selected G729 as the audio codec. The first packet we receive might be G711 though. In that case we will need to change. But only if we have a matching alternate codec payload_type. E.g. in the case of comfort noise we will receive the PT=11 and we don't want to change. --- openbsc/src/libmgcp/mgcp_transcode.c | 54 +++++++++++++++++- openbsc/tests/mgcp/mgcp_transcoding_test.c | 61 +++++++++++++++++++++ openbsc/tests/mgcp/mgcp_transcoding_test.ok | 1 + 3 files changed, 115 insertions(+), 1 deletion(-) diff --git a/openbsc/src/libmgcp/mgcp_transcode.c b/openbsc/src/libmgcp/mgcp_transcode.c index e961ba6cc..38daeb8ae 100644 --- a/openbsc/src/libmgcp/mgcp_transcode.c +++ b/openbsc/src/libmgcp/mgcp_transcode.c @@ -397,11 +397,62 @@ static int encode_audio(struct mgcp_process_rtp_state *state, return nbytes; } +static struct mgcp_rtp_end *source_for_dest(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end) +{ + if (&endp->bts_end == dst_end) + return &endp->net_end; + else if (&endp->net_end == dst_end) + return &endp->bts_end; + OSMO_ASSERT(0); +} + +/* + * With some modems we get offered multiple codecs + * and we have selected one of them. It might not + * be the right one and we need to detect this with + * the first audio packets. One difficulty is that + * we patch the rtp payload type in place, so we + * need to discuss this. + */ +struct mgcp_process_rtp_state *check_transcode_state( + struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, + struct rtp_hdr *rtp_hdr) +{ + struct mgcp_rtp_end *src_end; + + /* Only deal with messages from net to bts */ + if (&endp->bts_end != dst_end) + goto done; + + src_end = source_for_dest(endp, dst_end); + + /* Already patched */ + if (rtp_hdr->payload_type == dst_end->codec.payload_type) + goto done; + /* The payload we expect */ + if (rtp_hdr->payload_type == src_end->codec.payload_type) + goto done; + /* The matching alternate payload type? Then switch */ + if (rtp_hdr->payload_type == src_end->alt_codec.payload_type) { + struct mgcp_config *cfg = endp->cfg; + struct mgcp_rtp_codec tmp_codec = src_end->alt_codec; + src_end->alt_codec = src_end->codec; + src_end->codec = tmp_codec; + cfg->setup_rtp_processing_cb(endp, &endp->net_end, &endp->bts_end); + cfg->setup_rtp_processing_cb(endp, &endp->bts_end, &endp->net_end); + } + +done: + return dst_end->rtp_process_data; +} + int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end, char *data, int *len, int buf_size) { - struct mgcp_process_rtp_state *state = dst_end->rtp_process_data; + struct mgcp_process_rtp_state *state; const size_t rtp_hdr_size = sizeof(struct rtp_hdr); struct rtp_hdr *rtp_hdr = (struct rtp_hdr *) data; char *payload_data = (char *) &rtp_hdr->data[0]; @@ -414,6 +465,7 @@ int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, uint32_t ts_no; int rc; + state = check_transcode_state(endp, dst_end, rtp_hdr); if (!state) return 0; diff --git a/openbsc/tests/mgcp/mgcp_transcoding_test.c b/openbsc/tests/mgcp/mgcp_transcoding_test.c index 079f62eba..cf679b356 100644 --- a/openbsc/tests/mgcp/mgcp_transcoding_test.c +++ b/openbsc/tests/mgcp/mgcp_transcoding_test.c @@ -174,6 +174,9 @@ static int given_configured_endpoint(int in_samples, int out_samples, tcfg = talloc_zero(cfg, struct mgcp_trunk_config); endp = talloc_zero(tcfg, struct mgcp_endpoint); + cfg->setup_rtp_processing_cb = mgcp_transcoding_setup; + cfg->rtp_processing_cb = mgcp_transcoding_process_rtp; + cfg->get_net_downlink_format_cb = mgcp_transcoding_net_downlink_format; tcfg->endpoints = endp; tcfg->number_endpoints = 1; @@ -433,6 +436,63 @@ static void test_transcode_result(void) } } +static void test_transcode_change(void) +{ + char buf[4096] = {0x80, 0}; + void *ctx; + + struct mgcp_endpoint *endp; + struct mgcp_process_rtp_state *state; + struct rtp_hdr *hdr; + + int len, res; + + { + /* from GSM to PCMA and same ptime */ + printf("Testing Initial G729->GSM, PCMA->GSM\n"); + given_configured_endpoint(160, 0, "g729", "gsm", &ctx, &endp); + endp->net_end.alt_codec = endp->net_end.codec; + endp->net_end.alt_codec.payload_type = audio_name_to_type("pcma"); + state = endp->bts_end.rtp_process_data; + + /* initial transcoding work */ + OSMO_ASSERT(state->src_fmt == AF_G729); + OSMO_ASSERT(state->dst_fmt == AF_GSM); + OSMO_ASSERT(endp->net_end.alt_codec.payload_type == 8); + OSMO_ASSERT(endp->net_end.codec.payload_type == 18); + + /* result */ + len = audio_packets_pcma[0].len; + memcpy(buf, audio_packets_pcma[0].data, len); + res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf)); + OSMO_ASSERT(res == sizeof(struct rtp_hdr)); + OSMO_ASSERT(state->sample_cnt == 0); + OSMO_ASSERT(state->src_fmt == AF_PCMA); + OSMO_ASSERT(state->dst_fmt == AF_GSM); + OSMO_ASSERT(endp->net_end.alt_codec.payload_type == 18); + OSMO_ASSERT(endp->net_end.codec.payload_type == 8); + + len = res; + res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf)); + OSMO_ASSERT(res == -ENOMSG); + + + /* now check that comfort noise doesn't change anything */ + len = audio_packets_pcma[1].len; + memcpy(buf, audio_packets_pcma[1].data, len); + hdr = (struct rtp_hdr *) buf; + hdr->payload_type = 11; + res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf)); + OSMO_ASSERT(state->sample_cnt == 80); + OSMO_ASSERT(state->src_fmt == AF_PCMA); + OSMO_ASSERT(state->dst_fmt == AF_GSM); + OSMO_ASSERT(endp->net_end.alt_codec.payload_type == 18); + OSMO_ASSERT(endp->net_end.codec.payload_type == 8); + + talloc_free(ctx); + } +} + static int test_repacking(int in_samples, int out_samples, int no_transcode) { char buf[4096] = {0x80, 0}; @@ -582,6 +642,7 @@ int main(int argc, char **argv) test_repacking(160, 100, 1); test_rtp_seq_state(); test_transcode_result(); + test_transcode_change(); return 0; } diff --git a/openbsc/tests/mgcp/mgcp_transcoding_test.ok b/openbsc/tests/mgcp/mgcp_transcoding_test.ok index 7c1c8cebd..5cfc2897e 100644 --- a/openbsc/tests/mgcp/mgcp_transcoding_test.ok +++ b/openbsc/tests/mgcp/mgcp_transcoding_test.ok @@ -536,3 +536,4 @@ got 1 pcma output frames (80 octets) count=12 generating 160 pcma input samples got 1 pcma output frames (80 octets) count=12 got 1 pcma output frames (80 octets) count=12 +Testing Initial G729->GSM, PCMA->GSM