Make RTP payload type configurable

For a long time the RTP payload type was hard-coded for outgoing
frames. The problem is that according to RFC 3551 only GSM FR has
a static payload type value (see table 4, value 3). For other
codecs the payload type may be negotiated between the both
sides dynamically (i.e. in range 96-127).

Let's allow a binary/API user to configure this manually.

Change-Id: Ia07ed4e13b4a70c8bb4181564a8190861fd269da
Closes: OS#2482
This commit is contained in:
Vadim Yanitskiy 2018-07-09 20:09:50 +07:00
parent 62717b6375
commit 89c1082b3d
4 changed files with 64 additions and 18 deletions

View File

@ -89,8 +89,10 @@ int osmo_gapk_pq_queue_file_input(struct osmo_gapk_pq *pq, FILE *src, unsigned i
int osmo_gapk_pq_queue_file_output(struct osmo_gapk_pq *pq, FILE *dst, unsigned int block_len); int osmo_gapk_pq_queue_file_output(struct osmo_gapk_pq *pq, FILE *dst, unsigned int block_len);
/* RTP */ /* RTP */
int osmo_gapk_pq_queue_rtp_input(struct osmo_gapk_pq *pq, int rtp_fd, unsigned int block_len); int osmo_gapk_pq_queue_rtp_input(struct osmo_gapk_pq *pq, int rtp_fd,
int osmo_gapk_pq_queue_rtp_output(struct osmo_gapk_pq *pq, int rtp_fd, unsigned int block_len); unsigned int block_len, uint8_t pt);
int osmo_gapk_pq_queue_rtp_output(struct osmo_gapk_pq *pq, int rtp_fd,
unsigned int block_len, uint8_t pt);
/* ALSA */ /* ALSA */
int osmo_gapk_pq_queue_alsa_input(struct osmo_gapk_pq *pq, const char *hwdev, unsigned int blk_len); int osmo_gapk_pq_queue_alsa_input(struct osmo_gapk_pq *pq, const char *hwdev, unsigned int blk_len);

View File

@ -64,6 +64,9 @@ struct gapk_options
const char *alsa_out; const char *alsa_out;
const struct osmo_gapk_format_desc *fmt_out; const struct osmo_gapk_format_desc *fmt_out;
/* RTP payload type */
uint8_t rtp_pt_in, rtp_pt_out;
int benchmark; int benchmark;
int verbose; int verbose;
}; };
@ -133,6 +136,8 @@ print_help(char *progname)
#endif #endif
fprintf(stdout, " -f, --input-format=FMT\tInput format (see below)\n"); fprintf(stdout, " -f, --input-format=FMT\tInput format (see below)\n");
fprintf(stdout, " -g, --output-format=FMT\tOutput format (see below)\n"); fprintf(stdout, " -g, --output-format=FMT\tOutput format (see below)\n");
fprintf(stdout, " -p --rtp-pt-in=TYPE\t\tRTP payload type for incoming frames\n");
fprintf(stdout, " -P --rtp-pt-out=TYPE\t\tRTP payload type for outgoing frames\n");
fprintf(stdout, " -b, --enable-benchmark\tEnable codec benchmarking\n"); fprintf(stdout, " -b, --enable-benchmark\tEnable codec benchmarking\n");
fprintf(stdout, " -v, --verbose\t\t\tEnable debug messages\n"); fprintf(stdout, " -v, --verbose\t\t\tEnable debug messages\n");
fprintf(stdout, "\n"); fprintf(stdout, "\n");
@ -203,11 +208,13 @@ parse_options(struct gapk_state *state, int argc, char *argv[])
#endif #endif
{"input-format", 1, 0, 'f'}, {"input-format", 1, 0, 'f'},
{"output-format", 1, 0, 'g'}, {"output-format", 1, 0, 'g'},
{"rtp-pt-in", 1, 0, 'p'},
{"rtp-pt-out", 1, 0, 'P'},
{"enable-benchmark", 0, 0, 'b'}, {"enable-benchmark", 0, 0, 'b'},
{"verbose", 0, 0, 'v'}, {"verbose", 0, 0, 'v'},
{"help", 0, 0, 'h'}, {"help", 0, 0, 'h'},
}; };
const char *short_options = "i:o:I:O:f:g:bvh" const char *short_options = "i:o:I:O:f:g:p:P:bvh"
#ifdef HAVE_ALSA #ifdef HAVE_ALSA
"a:A:" "a:A:"
#endif #endif
@ -218,6 +225,10 @@ parse_options(struct gapk_state *state, int argc, char *argv[])
/* Set some defaults */ /* Set some defaults */
memset(opt, 0x00, sizeof(*opt)); memset(opt, 0x00, sizeof(*opt));
/* Default RTP payload type (GSM FR, see RFC 3551) */
opt->rtp_pt_in = 3;
opt->rtp_pt_out = 3;
/* Parse */ /* Parse */
while (1) { while (1) {
int c, rv; int c, rv;
@ -279,6 +290,24 @@ parse_options(struct gapk_state *state, int argc, char *argv[])
} }
break; break;
case 'p':
rv = atoi(optarg);
if (rv < 0 || rv > 0xff) {
LOGP(DAPP, LOGL_ERROR, "Invalid RTP payload type: %d\n", rv);
return -EINVAL;
}
opt->rtp_pt_in = rv;
break;
case 'P':
rv = atoi(optarg);
if (rv < 0 || rv > 0xff) {
LOGP(DAPP, LOGL_ERROR, "Invalid RTP payload type: %d\n", rv);
return -EINVAL;
}
opt->rtp_pt_out = rv;
break;
case 'b': case 'b':
opt->benchmark = 1; opt->benchmark = 1;
break; break;
@ -540,7 +569,8 @@ make_processing_chain(struct gapk_state *gs)
if (gs->in.file.fh) if (gs->in.file.fh)
osmo_gapk_pq_queue_file_input(gs->pq, gs->in.file.fh, fmt_in->frame_len); osmo_gapk_pq_queue_file_input(gs->pq, gs->in.file.fh, fmt_in->frame_len);
else if (gs->in.rtp.fd != -1) else if (gs->in.rtp.fd != -1)
osmo_gapk_pq_queue_rtp_input(gs->pq, gs->in.rtp.fd, fmt_in->frame_len); osmo_gapk_pq_queue_rtp_input(gs->pq, gs->in.rtp.fd,
fmt_in->frame_len, gs->opts.rtp_pt_in);
#ifdef HAVE_ALSA #ifdef HAVE_ALSA
else if (gs->opts.alsa_in) else if (gs->opts.alsa_in)
osmo_gapk_pq_queue_alsa_input(gs->pq, gs->opts.alsa_in, fmt_in->frame_len); osmo_gapk_pq_queue_alsa_input(gs->pq, gs->opts.alsa_in, fmt_in->frame_len);
@ -618,7 +648,8 @@ make_processing_chain(struct gapk_state *gs)
if (gs->out.file.fh) if (gs->out.file.fh)
osmo_gapk_pq_queue_file_output(gs->pq, gs->out.file.fh, fmt_out->frame_len); osmo_gapk_pq_queue_file_output(gs->pq, gs->out.file.fh, fmt_out->frame_len);
else if (gs->out.rtp.fd != -1) else if (gs->out.rtp.fd != -1)
osmo_gapk_pq_queue_rtp_output(gs->pq, gs->out.rtp.fd, fmt_out->frame_len); osmo_gapk_pq_queue_rtp_output(gs->pq, gs->out.rtp.fd,
fmt_out->frame_len, gs->opts.rtp_pt_out);
#ifdef HAVE_ALSA #ifdef HAVE_ALSA
else if (gs->opts.alsa_out) else if (gs->opts.alsa_out)
osmo_gapk_pq_queue_alsa_output(gs->pq, gs->opts.alsa_out, fmt_out->frame_len); osmo_gapk_pq_queue_alsa_output(gs->pq, gs->opts.alsa_out, fmt_out->frame_len);

View File

@ -70,8 +70,6 @@ struct rtp_x_hdr {
#define RTP_VERSION 2 #define RTP_VERSION 2
#define RTP_PT_GSM_FULL 3
struct pq_state_rtp { struct pq_state_rtp {
int fd; int fd;
int blk_len; int blk_len;
@ -193,7 +191,8 @@ pq_cb_rtp_exit(void *_state)
} }
static int static int
pq_queue_rtp_op(struct osmo_gapk_pq *pq, int udp_fd, unsigned int blk_len, int in_out_n) pq_queue_rtp_op(struct osmo_gapk_pq *pq, int udp_fd,
unsigned int blk_len, int in_out_n, uint8_t pt)
{ {
struct osmo_gapk_pq_item *item; struct osmo_gapk_pq_item *item;
struct pq_state_rtp *state; struct pq_state_rtp *state;
@ -210,12 +209,20 @@ pq_queue_rtp_op(struct osmo_gapk_pq *pq, int udp_fd, unsigned int blk_len, int i
* per RTP frame */ * per RTP frame */
state->duration = 160; state->duration = 160;
/**
* RTP payload type according to RFC 3551,
* section "6. Payload Type Definitions".
*
* Only GSM FR has a static payload type value (see table 4).
* For other codecs the payload type may be negotiated
* between the both sides dynamically (i.e. in range 96-127).
*/
state->payload_type = pt;
if (in_out_n == 0) { if (in_out_n == 0) {
state->ssrc = rand(); state->ssrc = rand();
state->sequence = random(); state->sequence = random();
state->timestamp = random(); state->timestamp = random();
/* FIXME: other payload types!! */
state->payload_type = RTP_PT_GSM_FULL;
} }
item = osmo_gapk_pq_add_item(pq); item = osmo_gapk_pq_add_item(pq);
@ -248,24 +255,30 @@ pq_queue_rtp_op(struct osmo_gapk_pq *pq, int udp_fd, unsigned int blk_len, int i
* This typically only makes sense as first item in the queue * This typically only makes sense as first item in the queue
* \param pq Processing Queue to add this RTP input to * \param pq Processing Queue to add this RTP input to
* \param[in] udp_fd UDP file descriptor for the RTP input * \param[in] udp_fd UDP file descriptor for the RTP input
* \param[in] blk_len Block Length to read from RTP */ * \param[in] blk_len Block Length to read from RTP
* \param[in] pt Payload type according to RFC 3551
*/
int int
osmo_gapk_pq_queue_rtp_input(struct osmo_gapk_pq *pq, int udp_fd, unsigned int blk_len) osmo_gapk_pq_queue_rtp_input(struct osmo_gapk_pq *pq, int udp_fd,
unsigned int blk_len, uint8_t pt)
{ {
LOGPGAPK(LOGL_DEBUG, "PQ '%s': Adding RTP input (blk_len=%u)\n", LOGPGAPK(LOGL_DEBUG, "PQ '%s': Adding RTP input (blk_len=%u)\n",
pq->name, blk_len); pq->name, blk_len);
return pq_queue_rtp_op(pq, udp_fd, blk_len, 1); return pq_queue_rtp_op(pq, udp_fd, blk_len, 1, pt);
} }
/*! Add RTP output to processing queue. /*! Add RTP output to processing queue.
* This typically only makes sense as last item in the queue * This typically only makes sense as last item in the queue
* \param pq Processing Queue to add this RTP output to * \param pq Processing Queue to add this RTP output to
* \param[in] udp_fd UDP file descriptor for the RTP output * \param[in] udp_fd UDP file descriptor for the RTP output
* \param[in] blk_len Block Length to read from RTP */ * \param[in] blk_len Block Length to read from RTP
* \param[in] pt Payload type according to RFC 3551
*/
int int
osmo_gapk_pq_queue_rtp_output(struct osmo_gapk_pq *pq, int udp_fd, unsigned int blk_len) osmo_gapk_pq_queue_rtp_output(struct osmo_gapk_pq *pq, int udp_fd,
unsigned int blk_len, uint8_t pt)
{ {
LOGPGAPK(LOGL_DEBUG, "PQ '%s': Adding RTP output (blk_len=%u)\n", LOGPGAPK(LOGL_DEBUG, "PQ '%s': Adding RTP output (blk_len=%u)\n",
pq->name, blk_len); pq->name, blk_len);
return pq_queue_rtp_op(pq, udp_fd, blk_len, 0); return pq_queue_rtp_op(pq, udp_fd, blk_len, 0, pt);
} }

View File

@ -173,7 +173,7 @@ static int init_gen_queue(struct osmo_gapk_pq *pq,
} }
/* Init an RTP sink */ /* Init an RTP sink */
rc = osmo_gapk_pq_queue_rtp_output(pq, state->rtp_dst_fd, payload_len); rc = osmo_gapk_pq_queue_rtp_output(pq, state->rtp_dst_fd, payload_len, 0x00);
if (rc) { if (rc) {
printf("Could not init an RTP sink\n"); printf("Could not init an RTP sink\n");
return rc; return rc;
@ -210,7 +210,7 @@ static int init_chk_queue(struct osmo_gapk_pq *pq,
} }
/* Init an RTP source on any available port */ /* Init an RTP source on any available port */
rc = osmo_gapk_pq_queue_rtp_input(pq, state->rtp_src_fd, payload_len); rc = osmo_gapk_pq_queue_rtp_input(pq, state->rtp_src_fd, payload_len, 0x00);
if (rc) { if (rc) {
printf("Could not init an RTP sink\n"); printf("Could not init an RTP sink\n");
return rc; return rc;