Merge branch 'zecke/features/dynamic-codec-switch'
This commit is contained in:
commit
e3283ec3eb
|
@ -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);
|
||||
|
|
|
@ -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,14 @@ struct mgcp_rtp_end {
|
|||
/* in network byte order */
|
||||
int rtp_port, rtcp_port;
|
||||
|
||||
/* audio codec information */
|
||||
struct mgcp_rtp_codec codec;
|
||||
struct mgcp_rtp_codec alt_codec; /* TODO/XXX: make it generic */
|
||||
|
||||
/* 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;
|
||||
|
||||
|
|
|
@ -35,4 +35,5 @@ struct rtp_hdr {
|
|||
uint16_t sequence;
|
||||
uint32_t timestamp;
|
||||
uint32_t ssrc;
|
||||
uint8_t data[0];
|
||||
} __attribute__((packed));
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
|
@ -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, 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,23 +773,29 @@ 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)
|
||||
/* 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 */
|
||||
rtp->packet_duration_ms = 0;
|
||||
}
|
||||
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, audio_payload, NULL);
|
||||
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;
|
||||
}
|
||||
|
@ -814,8 +824,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 +882,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 +1035,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 +1157,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);
|
||||
|
@ -1449,6 +1459,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 +1484,19 @@ 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->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->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->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->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)
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <openbsc/mgcp.h>
|
||||
#include <openbsc/mgcp_internal.h>
|
||||
#include <openbsc/mgcp_transcode.h>
|
||||
#include <openbsc/rtp.h>
|
||||
|
||||
#include <osmocom/core/talloc.h>
|
||||
|
||||
|
@ -44,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 */:
|
||||
|
@ -140,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) {
|
||||
|
@ -150,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;
|
||||
}
|
||||
|
||||
|
@ -268,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;
|
||||
}
|
||||
|
@ -280,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,
|
||||
|
@ -391,13 +397,65 @@ 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;
|
||||
size_t rtp_hdr_size = 12;
|
||||
char *payload_data = data + rtp_hdr_size;
|
||||
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];
|
||||
int payload_len = *len - rtp_hdr_size;
|
||||
uint8_t *src = (uint8_t *)payload_data;
|
||||
uint8_t *dst = (uint8_t *)payload_data;
|
||||
|
@ -407,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;
|
||||
|
||||
|
@ -427,9 +486,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 +563,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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* (C) 2011-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||
* (C) 2011-2012 by On-Waves
|
||||
* (C) 2011-2012,2014 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||
* (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;
|
||||
|
@ -410,7 +465,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 +553,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 +885,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;
|
||||
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
@ -183,14 +186,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;
|
||||
}
|
||||
|
@ -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};
|
||||
|
@ -463,7 +523,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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue