Skip to content

Commit

Permalink
rtp_engine: add support for multirate 2833 DRAFT
Browse files Browse the repository at this point in the history
DRAFT PR - demonstrate a method for handling non 8K
2833 digit sdp offers.

Changes to the engine itself limited to adding the 48/24K types.

res_pjsip_sdp_rtp is changed to note the number of incoming codecs
and add an associated offer
  • Loading branch information
mbradeen committed Dec 11, 2023
1 parent 31c44d0 commit df8b425
Show file tree
Hide file tree
Showing 4 changed files with 204 additions and 17 deletions.
32 changes: 32 additions & 0 deletions include/asterisk/rtp_engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,8 @@ struct ast_rtp_payload_type {
unsigned int primary_mapping:1;
/*! When the payload type became non-primary. */
struct timeval when_retired;
/*! Bitrate to over-ride mime type defaults */
int bitrate;

This comment has been minimized.

Copy link
@jcolp

jcolp Dec 12, 2023

It's referred to as sample rate

};

/* Common RTCP report types */
Expand Down Expand Up @@ -1788,6 +1790,21 @@ int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_form
*/
int ast_rtp_codecs_payload_set_rx(struct ast_rtp_codecs *codecs, int code, struct ast_format *format);

/*!
* \brief Set a payload code with bitrate for use with a specific Asterisk format
*
* \param codecs Codecs structure to manipulate
* \param code The payload code
* \param format Asterisk format
* \param bitrate Bitrate of the format, 0 to use the format's default
*
* \retval 0 Payload was set to the given format
* \retval -1 Payload was in use or could not be set
*
* \since 20.0.0
*/
int ast_rtp_codecs_payload_set_rx_bitrate(struct ast_rtp_codecs *codecs, int code, struct ast_format *format, int bitrate);

/*!
* \brief Retrieve a tx mapped payload type based on whether it is an Asterisk format and the code
* \since 14.0.0
Expand All @@ -1802,6 +1819,21 @@ int ast_rtp_codecs_payload_set_rx(struct ast_rtp_codecs *codecs, int code, struc
*/
int ast_rtp_codecs_payload_code_tx(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code);

/*!
* \brief Retrieve a tx mapped payload type based on whether it is an Asterisk format and the code
* \since 20.0.0
*
* \param codecs Codecs structure to look in
* \param asterisk_format Non-zero if the given Asterisk format is present
* \param format Asterisk format to look for
* \param code The format to look for
* \param bitrate The bitrate to look for, zero if we don't care
*
* \return Numerical payload type
* \retval -1 if not found.
*/
int ast_rtp_codecs_payload_code_tx_bitrate(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code, int bitrate);

/*!
* \brief Search for the tx payload type in the ast_rtp_codecs structure
*
Expand Down
33 changes: 28 additions & 5 deletions main/rtp_engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -1380,6 +1380,8 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs,
continue;
}

ast_log(LOG_DEBUG, "Comparing %d %s %s with %d %s %s", pt, mimetype, mimesubtype, t->payload_type.rtp_code, t->type, t->subtype);

/* if both sample rates have been supplied, and they don't match,
* then this not a match; if one has not been supplied, then the
* rates are not compared */
Expand All @@ -1399,6 +1401,7 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs,
new_type->rtp_code = t->payload_type.rtp_code;
new_type->payload = pt;
new_type->primary_mapping = 1;
new_type->bitrate = sample_rate;
if (t->payload_type.asterisk_format
&& ast_format_cmp(t->payload_type.format, ast_format_g726) == AST_FORMAT_CMP_EQUAL
&& (options & AST_RTP_OPT_G726_NONSTANDARD)) {
Expand Down Expand Up @@ -1825,7 +1828,7 @@ static int rtp_codecs_find_non_primary_dynamic_rx(struct ast_rtp_codecs *codecs)
* \return Numerical payload type
* \retval -1 if could not assign.
*/
static int rtp_codecs_assign_payload_code_rx(struct ast_rtp_codecs *codecs, int asterisk_format, struct ast_format *format, int code, int explicit)
static int rtp_codecs_assign_payload_code_rx(struct ast_rtp_codecs *codecs, int asterisk_format, struct ast_format *format, int code, int explicit, int bitrate)
{
int payload = code;
struct ast_rtp_payload_type *new_type;
Expand All @@ -1844,8 +1847,13 @@ static int rtp_codecs_assign_payload_code_rx(struct ast_rtp_codecs *codecs, int
}

ast_rwlock_wrlock(&codecs->codecs_lock);

new_type->bitrate = bitrate;

if (payload > -1 && (payload < AST_RTP_PT_FIRST_DYNAMIC
|| AST_VECTOR_SIZE(&codecs->payload_mapping_rx) <= payload
// test if this is needed
//|| (explicit || !AST_VECTOR_GET(&codecs->payload_mapping_rx, payload)))) {
|| !AST_VECTOR_GET(&codecs->payload_mapping_rx, payload))) {
/*
* The payload type is a static assignment
Expand Down Expand Up @@ -1926,7 +1934,7 @@ int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_form

if (payload < 0) {
payload = rtp_codecs_assign_payload_code_rx(codecs, asterisk_format, format,
code, 0);
code, 0, 0);
}
ast_rwlock_unlock(&static_RTP_PT_lock);

Expand All @@ -1935,10 +1943,15 @@ int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_form

int ast_rtp_codecs_payload_set_rx(struct ast_rtp_codecs *codecs, int code, struct ast_format *format)
{
return rtp_codecs_assign_payload_code_rx(codecs, 1, format, code, 1);
return rtp_codecs_assign_payload_code_rx(codecs, 1, format, code, 1, 0);
}

int ast_rtp_codecs_payload_code_tx(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code)
int ast_rtp_codecs_payload_set_rx_bitrate(struct ast_rtp_codecs *codecs, int code, struct ast_format *format, int bitrate)
{
return rtp_codecs_assign_payload_code_rx(codecs, 1, format, code, 0, bitrate);
}

int ast_rtp_codecs_payload_code_tx_bitrate(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code, int bitrate)
{
struct ast_rtp_payload_type *type;
int idx;
Expand All @@ -1953,7 +1966,8 @@ int ast_rtp_codecs_payload_code_tx(struct ast_rtp_codecs *codecs, int asterisk_f
}

if (!type->asterisk_format
&& type->rtp_code == code) {
&& type->rtp_code == code
&& (!bitrate || type->bitrate == bitrate)) {
payload = idx;
break;
}
Expand Down Expand Up @@ -1985,6 +1999,11 @@ int ast_rtp_codecs_payload_code_tx(struct ast_rtp_codecs *codecs, int asterisk_f
return payload;
}

int ast_rtp_codecs_payload_code_tx(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code)
{
return ast_rtp_codecs_payload_code_tx_bitrate(codecs, asterisk_format, format, code, 0);
}

int ast_rtp_codecs_find_payload_code(struct ast_rtp_codecs *codecs, int payload)
{
struct ast_rtp_payload_type *type;
Expand Down Expand Up @@ -3700,7 +3719,11 @@ int ast_rtp_engine_init(void)
/* this is the sample rate listed in the RTP profile for the G.722 codec, *NOT* the actual sample rate of the media stream */
set_next_mime_type(ast_format_g722, 0, "audio", "G722", 8000);
set_next_mime_type(ast_format_g726_aal2, 0, "audio", "AAL2-G726-32", 8000);
/* we need all 4 of these or ast_rtp_codecs_payloads_set_rtpmap_type_rate will not examine it */
set_next_mime_type(NULL, AST_RTP_DTMF, "audio", "telephone-event", 8000);
set_next_mime_type(NULL, AST_RTP_DTMF, "audio", "telephone-event", 16000);
set_next_mime_type(NULL, AST_RTP_DTMF, "audio", "telephone-event", 48000);
set_next_mime_type(NULL, AST_RTP_DTMF, "audio", "telephone-event", 24000);
set_next_mime_type(NULL, AST_RTP_CISCO_DTMF, "audio", "cisco-telephone-event", 8000);
set_next_mime_type(NULL, AST_RTP_CN, "audio", "CN", 8000);
set_next_mime_type(ast_format_jpeg, 0, "video", "JPEG", 90000);
Expand Down
119 changes: 111 additions & 8 deletions res/res_pjsip_sdp_rtp.c
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,43 @@ static pjmedia_sdp_attr* generate_rtpmap_attr(struct ast_sip_session *session, p
return attr;
}


static pjmedia_sdp_attr* generate_rtpmap_attr2(struct ast_sip_session *session, pjmedia_sdp_media *media, pj_pool_t *pool,
int rtp_code, int asterisk_format, struct ast_format *format, int code, int sample_rate)
{
#ifndef HAVE_PJSIP_ENDPOINT_COMPACT_FORM
extern pj_bool_t pjsip_use_compact_form;
#else
pj_bool_t pjsip_use_compact_form = pjsip_cfg()->endpt.use_compact_form;
#endif
pjmedia_sdp_rtpmap rtpmap;
pjmedia_sdp_attr *attr = NULL;
char tmp[64];
enum ast_rtp_options options = session->endpoint->media.g726_non_standard ?
AST_RTP_OPT_G726_NONSTANDARD : 0;

snprintf(tmp, sizeof(tmp), "%d", rtp_code);
pj_strdup2(pool, &media->desc.fmt[media->desc.fmt_count++], tmp);

if (rtp_code <= AST_RTP_PT_LAST_STATIC && pjsip_use_compact_form) {
return NULL;
}

rtpmap.pt = media->desc.fmt[media->desc.fmt_count - 1];
rtpmap.clock_rate = sample_rate;
ast_log(LOG_ERROR, "Generating rtpmap attribute with clock rate: %d\n", rtpmap.clock_rate);
pj_strdup2(pool, &rtpmap.enc_name, ast_rtp_lookup_mime_subtype2(asterisk_format, format, code, options));
if (!pj_stricmp2(&rtpmap.enc_name, "opus")) {
pj_cstr(&rtpmap.param, "2");
} else {
pj_cstr(&rtpmap.param, NULL);
}

pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);

return attr;
}

static pjmedia_sdp_attr* generate_fmtp_attr(pj_pool_t *pool, struct ast_format *format, int rtp_code)
{
struct ast_str *fmtp0 = ast_str_alloca(256);
Expand Down Expand Up @@ -1749,6 +1786,11 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as
pj_sockaddr ip;
int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) &&
ast_format_cap_count(session->direct_media_cap);

int bitRates[4] = { 0, 0, 0, 0 };
int added_rtp_type = 0;
struct ast_rtp_codecs *zcodecs;

SCOPE_ENTER(1, "%s Type: %s %s\n", ast_sip_session_get_name(session),
ast_codec_media_type2str(media_type), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));

Expand Down Expand Up @@ -1938,7 +1980,27 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as
}

if ((attr = generate_rtpmap_attr(session, media, pool, rtp_code, 1, format, 0))) {
int newrate = ast_rtp_lookup_sample_rate2(1, format, 0);
media->attr[media->attr_count++] = attr;
// lolcode
if (bitRates[0] == 0) {
bitRates[0] = newrate;
}
else if ((newrate != bitRates[0])) {
if (bitRates[1] == 0) {
bitRates[1] = newrate;
}
else if ((newrate != bitRates[1])) {
if (bitRates[2] == 0) {
bitRates[2] = newrate;
}
else if ((newrate != bitRates[2])) {
if (bitRates[3] == 0) {
bitRates[3] = newrate;
}
}
}
}
}

if ((attr = generate_fmtp_attr(pool, format, rtp_code))) {
Expand All @@ -1956,6 +2018,38 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as
}
}

/* Copy any non asterisk formats to the rx side */
zcodecs = ast_rtp_instance_get_codecs(session_media->rtp);
for (int idx = 0; idx < AST_VECTOR_SIZE(&zcodecs->payload_mapping_tx); ++idx) {
struct ast_rtp_payload_type *type;
type = AST_VECTOR_GET(&zcodecs->payload_mapping_tx, idx);
if (!type) {
continue;
}
if (!type->asterisk_format && type->primary_mapping) {
ast_rtp_codecs_payload_set_rx_bitrate(ast_rtp_instance_get_codecs(session_media->rtp), idx, type->format, type->bitrate);
}
}
/* Use the rx list of non asterisk formats to build the sdp attributes */
for (int idx = 0; idx < AST_VECTOR_SIZE(&zcodecs->payload_mapping_rx); ++idx) {

This comment has been minimized.

Copy link
@jcolp

jcolp Dec 12, 2023

codecs should be considered opaque

struct ast_rtp_payload_type *type;
type = AST_VECTOR_GET(&zcodecs->payload_mapping_rx, idx);
if (!type) {
continue;
}
if (!type->asterisk_format && type->primary_mapping) {
int newrate = type->bitrate;
if ((attr = generate_rtpmap_attr2(session, media, pool, idx, 0, NULL, AST_RTP_DTMF, newrate))) {
/* note that we are adding attributes based on an existing offer so they don't need to be made from scratch */
added_rtp_type = 1;
media->attr[media->attr_count++] = attr;
snprintf(tmp, sizeof(tmp), "%d 0-16", (idx));
attr = pjmedia_sdp_attr_create(pool, "fmtp", pj_cstr(&stmp, tmp));
media->attr[media->attr_count++] = attr;
}
}
}

/* Add non-codec formats */
if (ast_sip_session_is_pending_stream_default(session, stream) && media_type != AST_MEDIA_TYPE_VIDEO
&& media->desc.fmt_count < PJMEDIA_MAX_SDP_FMT) {
Expand All @@ -1969,14 +2063,24 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as
continue;
}

if ((attr = generate_rtpmap_attr(session, media, pool, rtp_code, 0, NULL, index))) {
media->attr[media->attr_count++] = attr;
if (index != AST_RTP_DTMF) {
if ((attr = generate_rtpmap_attr(session, media, pool, rtp_code, 0, NULL, index))) {
media->attr[media->attr_count++] = attr;
}
}

if (index == AST_RTP_DTMF) {
snprintf(tmp, sizeof(tmp), "%d 0-16", rtp_code);
attr = pjmedia_sdp_attr_create(pool, "fmtp", pj_cstr(&stmp, tmp));
media->attr[media->attr_count++] = attr;
else if (!added_rtp_type) {
/* If we aren't going based off an existing offer, walk through the possible bitrates for the
2833/4733 digits and add them manually */
for (int i=0; i<4; i++) {
if(bitRates[i] != 0 ) {
if ((attr = generate_rtpmap_attr2(session, media, pool, (rtp_code+i), 0, NULL, index, bitRates[i]))) {
media->attr[media->attr_count++] = attr;
}
snprintf(tmp, sizeof(tmp), "%d 0-16", (rtp_code+i));
attr = pjmedia_sdp_attr_create(pool, "fmtp", pj_cstr(&stmp, tmp));
media->attr[media->attr_count++] = attr;
}
}
}

if (media->desc.fmt_count == PJMEDIA_MAX_SDP_FMT) {
Expand All @@ -1985,7 +2089,6 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as
}
}


/* If no formats were actually added to the media stream don't add it to the SDP */
if (!media->desc.fmt_count) {
SCOPE_EXIT_RTN_VALUE(1, "No formats added to stream\n");
Expand Down
37 changes: 33 additions & 4 deletions res/res_rtp_asterisk.c
Original file line number Diff line number Diff line change
Expand Up @@ -4204,7 +4204,7 @@ static int ast_rtp_dtmf_begin(struct ast_rtp_instance *instance, char digit)
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
struct ast_sockaddr remote_address = { {0,} };
int hdrlen = 12, res = 0, i = 0, payload = 101;
int hdrlen = 12, res = 0, i = 0, payload = 101, sample_rate = 8000;
char data[256];
unsigned int *rtpheader = (unsigned int*)data;

Expand All @@ -4231,12 +4231,41 @@ static int ast_rtp_dtmf_begin(struct ast_rtp_instance *instance, char digit)
return -1;
}

/* Grab the payload that they expect the RFC2833 packet to be received in */
payload = ast_rtp_codecs_payload_code_tx(ast_rtp_instance_get_codecs(instance), 0, NULL, AST_RTP_DTMF);
if (rtp->lasttxformat == ast_format_none) {

This comment has been minimized.

Copy link
@jcolp

jcolp Dec 12, 2023

same here - opaque

/* we haven't sent any audio yet so we have to lookup both the payload type and
bitrate. This should get us the first stored dtmf type. */
struct ast_rtp_payload_type *type;
int idx;
struct ast_rtp_codecs *codecs = ast_rtp_instance_get_codecs(instance);
ast_rwlock_rdlock(&codecs->codecs_lock);
for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_tx); ++idx) {
type = AST_VECTOR_GET(&codecs->payload_mapping_tx, idx);
if (!type) {
continue;
}
if (type->rtp_code == AST_RTP_DTMF) {
payload = idx;
sample_rate = type->bitrate;
break;
}
}
ast_rwlock_unlock(&codecs->codecs_lock);
} else {
/* If we get 0 back that can be ok, provided a default rate is set */
sample_rate = ast_format_get_codec(rtp->lasttxformat)->sample_rate;

This comment has been minimized.

Copy link
@jcolp

jcolp Dec 12, 2023

this should use ast_rtp_get_rate

/* Grab the payload that they expect the RFC2833 packet to be received in */
payload = ast_rtp_codecs_payload_code_tx_bitrate(ast_rtp_instance_get_codecs(instance), 0, NULL, AST_RTP_DTMF, sample_rate);
}
/* If this returns -1, we are being asked to send digits for a sample rate that is outside
what was negotiated for. Fall back if possible. */
if (payload == -1) {
return -1;
}
ast_log(LOG_DEBUG, "Sending digit '%d' at rate %d\n", digit, sample_rate);

rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
rtp->send_duration = 160;
rtp->lastts += calc_txstamp(rtp, NULL) * DTMF_SAMPLE_RATE_MS;
rtp->lastts += calc_txstamp(rtp, NULL) * (sample_rate/1000);
rtp->lastdigitts = rtp->lastts + rtp->send_duration;

/* Create the actual packet that we will be sending */
Expand Down

0 comments on commit df8b425

Please sign in to comment.