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.
This commit is contained in:
Holger Hans Peter Freyther 2014-09-01 10:35:55 +02:00
parent 3713f78ac2
commit cac2438b0c
9 changed files with 111 additions and 97 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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",

View File

@ -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;
}

View File

@ -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,

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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);