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