res_rtp_asterisk: Add support for raising additional RTCP messages.

This change extends the existing AST_FRAME_RTCP frame type to be
able to contain additional RTCP message types, such as feedback
messages. The payload type is contained in the subclass which allows
knowing what is in the frame itself.

The RTCP feedback message type is now handled and REMB[1] messages
are raised with their containing information.

This also fixes a bug where all feedback messages were triggering
video updates instead of just FIR and FUR.

Finally RTCP frames are now passed up through the Asterisk core to
what is handling the channel, mapped appropriately in the case of
bridging, and written to an outgoing stream. Since RTCP frames are
on a per-stream basis this is only done on multistream capable
channels.

[1] https://tools.ietf.org/html/draft-alvestrand-rmcat-remb-03

ASTERISK-27758
ASTERISK-26366

Change-Id: I680da0ad8d5059d5e9655d896fb9d92e9da8491e
remotes/origin/16.0
Joshua Colp 7 years ago
parent a4a5b8d562
commit e14b0e960d

@ -965,6 +965,8 @@ static int chan_pjsip_write_stream(struct ast_channel *ast, int stream_num, stru
break;
case AST_FRAME_CNG:
break;
case AST_FRAME_RTCP:
break;
default:
ast_log(LOG_WARNING, "Can't send %u type frames with PJSIP\n", frame->frametype);
break;

@ -372,6 +372,11 @@ static void lintospeex_feedback(struct ast_trans_pvt *pvt, struct ast_frame *fee
if(!exp_rtcp_fb)
return;
/* We only accept feedback information in the form of SR and RR reports */
if (feedback->subclass.integer != AST_RTP_RTCP_SR && feedback->subclass.integer != AST_RTP_RTCP_RR) {
return;
}
rtcp_report = (struct ast_rtp_rtcp_report *)feedback->data.ptr;
if (rtcp_report->reception_report_count == 0)
return;

@ -127,7 +127,7 @@ enum ast_frame_type {
* directly into bridges.
*/
AST_FRAME_BRIDGE_ACTION_SYNC,
/*! RTCP feedback */
/*! RTCP feedback (the subclass will contain the payload type) */
AST_FRAME_RTCP,
};
#define AST_FRAME_DTMF AST_FRAME_DTMF_END

@ -292,6 +292,14 @@ struct ast_rtp_payload_type {
#define AST_RTP_RTCP_SR 200
/*! Receiver Report */
#define AST_RTP_RTCP_RR 201
/*! Payload Specific Feed Back (From RFC4585 also RFC5104) */
#define AST_RTP_RTCP_PSFB 206
/* Common RTCP feedback message types */
/*! Full INTRA-frame Request (From RFC5104) */
#define AST_RTP_RTCP_FMT_FIR 4
/*! REMB Information (From draft-alvestrand-rmcat-remb-03) */
#define AST_RTP_RTCP_FMT_REMB 15
/*!
* \since 12
@ -327,6 +335,24 @@ struct ast_rtp_rtcp_report {
struct ast_rtp_rtcp_report_block *report_block[0];
};
/*!
* \since 15.4.0
* \brief A REMB feedback message (see draft-alvestrand-rmcat-remb-03 for details) */
struct ast_rtp_rtcp_feedback_remb {
unsigned int br_exp; /*!< Exponential scaling of the mantissa for the maximum total media bit rate value */
unsigned int br_mantissa; /*!< The mantissa of the maximum total media bit rate */
};
/*!
* \since 15.4.0
* \brief An object that represents data received in a feedback report */
struct ast_rtp_rtcp_feedback {
unsigned int fmt; /*!< The feedback message type */
union {
struct ast_rtp_rtcp_feedback_remb remb; /*!< REMB feedback information */
};
};
/*! Structure that represents statistics from an RTP instance */
struct ast_rtp_instance_stats {
/*! Number of packets transmitted */

@ -653,7 +653,8 @@ static int bridge_channel_write_frame(struct ast_bridge_channel *bridge_channel,
case AST_FRAME_VIDEO:
case AST_FRAME_TEXT:
case AST_FRAME_IMAGE:
/* Media frames need to be mapped to an appropriate write stream */
case AST_FRAME_RTCP:
/* These frames need to be mapped to an appropriate write stream */
if (frame->stream_num < 0) {
/* Map to default stream */
frame->stream_num = -1;

@ -4123,8 +4123,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int
if (ast_channel_writetrans(chan)) {
ast_translate(ast_channel_writetrans(chan), f, 0);
}
ast_frfree(f);
f = &ast_null_frame;
break;
default:
/* Just pass it on! */
break;
@ -5267,6 +5266,14 @@ int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame
/* Ignore these */
res = 0;
break;
case AST_FRAME_RTCP:
/* RTCP information is on a per-stream basis and only available on multistream capable channels */
if (ast_channel_tech(chan)->write_stream && stream) {
res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), fr);
} else {
res = 0;
}
break;
default:
/* At this point, fr is the incoming frame and f is NULL. Channels do
* not expect to get NULL as a frame pointer and will segfault. Hence,

@ -106,7 +106,7 @@
#define RTCP_PT_APP 204
/* VP8: RTCP Feedback */
/*! Payload Specific Feed Back (From RFC4585 also RFC5104) */
#define RTCP_PT_PSFB 206
#define RTCP_PT_PSFB AST_RTP_RTCP_PSFB
#define RTP_MTU 1200
#define DTMF_SAMPLE_RATE_MS 8 /*!< DTMF samples per millisecond */
@ -5185,6 +5185,7 @@ static const char *rtcp_payload_type2str(unsigned int pt)
#define RTCP_SR_BLOCK_WORD_LENGTH 5
#define RTCP_RR_BLOCK_WORD_LENGTH 6
#define RTCP_HEADER_SSRC_LENGTH 2
#define RTCP_FB_REMB_BLOCK_WORD_LENGTH 5
static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, const unsigned char *rtcpdata, size_t size, struct ast_sockaddr *addr)
{
@ -5266,6 +5267,7 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c
RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report, NULL, ao2_cleanup);
struct ast_rtp_instance *child;
struct ast_rtp *rtp;
struct ast_rtp_rtcp_feedback *feedback;
i = position;
first_word = ntohl(rtcpheader[i]);
@ -5284,7 +5286,15 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c
min_length += (rc * RTCP_RR_BLOCK_WORD_LENGTH);
break;
case RTCP_PT_FUR:
break;
case RTCP_PT_PSFB:
switch (rc) {
case AST_RTP_RTCP_FMT_REMB:
min_length += RTCP_FB_REMB_BLOCK_WORD_LENGTH;
break;
default:
break;
}
break;
case RTCP_PT_SDES:
case RTCP_PT_BYE:
@ -5493,6 +5503,7 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c
/* Return an AST_FRAME_RTCP frame with the ast_rtp_rtcp_report
* object as a its data */
transport_rtp->f.frametype = AST_FRAME_RTCP;
transport_rtp->f.subclass.integer = pt;
transport_rtp->f.data.ptr = rtp->rtcp->frame_buf + AST_FRIENDLY_OFFSET;
memcpy(transport_rtp->f.data.ptr, rtcp_report, sizeof(struct ast_rtp_rtcp_report));
transport_rtp->f.datalen = sizeof(struct ast_rtp_rtcp_report);
@ -5514,18 +5525,55 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c
f = &transport_rtp->f;
break;
case RTCP_PT_FUR:
/* Handle RTCP FIR as FUR */
/* Handle RTCP FUR as FIR by setting the format to 4 */
rc = AST_RTP_RTCP_FMT_FIR;
case RTCP_PT_PSFB:
if (rtcp_debug_test_addr(addr)) {
ast_verbose("Received an RTCP Fast Update Request\n");
switch (rc) {
case AST_RTP_RTCP_FMT_FIR:
if (rtcp_debug_test_addr(addr)) {
ast_verbose("Received an RTCP Fast Update Request\n");
}
transport_rtp->f.frametype = AST_FRAME_CONTROL;
transport_rtp->f.subclass.integer = AST_CONTROL_VIDUPDATE;
transport_rtp->f.datalen = 0;
transport_rtp->f.samples = 0;
transport_rtp->f.mallocd = 0;
transport_rtp->f.src = "RTP";
f = &transport_rtp->f;
break;
case AST_RTP_RTCP_FMT_REMB:
/* If REMB support is not enabled ignore this message */
if (!ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_REMB)) {
break;
}
if (rtcp_debug_test_addr(addr)) {
ast_verbose("Received REMB report\n");
}
transport_rtp->f.frametype = AST_FRAME_RTCP;
transport_rtp->f.subclass.integer = pt;
transport_rtp->f.stream_num = rtp->stream_num;
transport_rtp->f.data.ptr = rtp->rtcp->frame_buf + AST_FRIENDLY_OFFSET;
feedback = transport_rtp->f.data.ptr;
feedback->fmt = rc;
/* We don't actually care about the SSRC information in the feedback message */
first_word = ntohl(rtcpheader[i + 2]);
feedback->remb.br_exp = (first_word >> 18) & ((1 << 6) - 1);
feedback->remb.br_mantissa = first_word & ((1 << 18) - 1);
transport_rtp->f.datalen = sizeof(struct ast_rtp_rtcp_feedback);
transport_rtp->f.offset = AST_FRIENDLY_OFFSET;
transport_rtp->f.samples = 0;
transport_rtp->f.mallocd = 0;
transport_rtp->f.delivery.tv_sec = 0;
transport_rtp->f.delivery.tv_usec = 0;
transport_rtp->f.src = "RTP";
f = &transport_rtp->f;
break;
default:
break;
}
transport_rtp->f.frametype = AST_FRAME_CONTROL;
transport_rtp->f.subclass.integer = AST_CONTROL_VIDUPDATE;
transport_rtp->f.datalen = 0;
transport_rtp->f.samples = 0;
transport_rtp->f.mallocd = 0;
transport_rtp->f.src = "RTP";
f = &transport_rtp->f;
break;
case RTCP_PT_SDES:
if (rtcp_debug_test_addr(addr)) {

Loading…
Cancel
Save