diff -urN asterisk-14.1.2/codecs/codec_speex.c asterisk-14.1.2-PATCHED/codecs/codec_speex.c
--- asterisk-14.1.2/codecs/codec_speex.c	2016-11-10 20:43:02.000000000 +0100
+++ asterisk-14.1.2-PATCHED/codecs/codec_speex.c	2016-11-11 14:38:04.408658123 +0100
@@ -57,6 +57,9 @@
 #include "asterisk/frame.h"
 #include "asterisk/linkedlists.h"
 
+/* For struct ast_rtp_rtcp_report and struct ast_rtp_rtcp_report_block */
+#include "asterisk/rtp_engine.h"
+
 /* codec variables */
 static int quality = 3;
 static int complexity = 2;
@@ -344,6 +347,21 @@
 	return result;
 }
 
+/*! \brief handle incoming RTCP feedback and possibly edit encoder settings */
+static void lintospeex_feedback(struct ast_trans_pvt *pvt, struct ast_frame *feedback)
+{
+	/* TODO */
+	ast_verb(3, "Got RTCP!\n");
+	struct ast_rtp_rtcp_report *rtcp_report = (struct ast_rtp_rtcp_report *)feedback->data.ptr;
+	ast_verb(3, "  -- type=%d\n", rtcp_report->type);
+	ast_verb(3, "  -- rc=%d\n", rtcp_report->reception_report_count);
+	if(rtcp_report->reception_report_count > 0) {
+		struct ast_rtp_rtcp_report_block *report_block = rtcp_report->report_block[0];
+		ast_verb(3, "  -- -- ssrc=%u\n", report_block->source_ssrc);
+		ast_verb(3, "  -- -- fraction=%u\n", report_block->lost_count.fraction);
+	}
+}
+
 static void speextolin_destroy(struct ast_trans_pvt *arg)
 {
 	struct speex_coder_pvt *pvt = arg->pvt;
@@ -402,6 +420,7 @@
 	.newpvt = lintospeex_new,
 	.framein = lintospeex_framein,
 	.frameout = lintospeex_frameout,
+	.feedback = lintospeex_feedback,
 	.destroy = lintospeex_destroy,
 	.sample = slin8_sample,
 	.desc_size = sizeof(struct speex_coder_pvt),
@@ -448,6 +467,7 @@
 	.newpvt = lin16tospeexwb_new,
 	.framein = lintospeex_framein,
 	.frameout = lintospeex_frameout,
+	.feedback = lintospeex_feedback,
 	.destroy = lintospeex_destroy,
 	.sample = slin16_sample,
 	.desc_size = sizeof(struct speex_coder_pvt),
@@ -493,6 +513,7 @@
 	.newpvt = lin32tospeexuwb_new,
 	.framein = lintospeex_framein,
 	.frameout = lintospeex_frameout,
+	.feedback = lintospeex_feedback,
 	.destroy = lintospeex_destroy,
 	.desc_size = sizeof(struct speex_coder_pvt),
 	.buffer_samples = BUFFER_SAMPLES,
diff -urN asterisk-14.1.2/include/asterisk/frame.h asterisk-14.1.2-PATCHED/include/asterisk/frame.h
--- asterisk-14.1.2/include/asterisk/frame.h	2016-11-10 20:43:02.000000000 +0100
+++ asterisk-14.1.2-PATCHED/include/asterisk/frame.h	2016-11-11 14:37:08.986415407 +0100
@@ -127,6 +127,8 @@
 	 * directly into bridges.
 	 */
 	AST_FRAME_BRIDGE_ACTION_SYNC,
+	/*! RTCP feedback */
+	AST_FRAME_RTCP,
 };
 #define AST_FRAME_DTMF AST_FRAME_DTMF_END
 
diff -urN asterisk-14.1.2/include/asterisk/translate.h asterisk-14.1.2-PATCHED/include/asterisk/translate.h
--- asterisk-14.1.2/include/asterisk/translate.h	2016-11-10 20:43:02.000000000 +0100
+++ asterisk-14.1.2-PATCHED/include/asterisk/translate.h	2016-11-11 14:37:08.987415413 +0100
@@ -121,7 +121,7 @@
  *
  * As a minimum, a translator should supply name, srcfmt and dstfmt,
  * the required buf_size (in bytes) and buffer_samples (in samples),
- * and a few callbacks (framein, frameout, sample).
+ * and a few callbacks (framein, frameout, feedback, sample).
  * The outbuf is automatically prepended by AST_FRIENDLY_OFFSET
  * spare bytes so generic routines can place data in there.
  *
@@ -159,6 +159,10 @@
 	                                       /*!< Output frame callback. Generate a frame 
 	                                        *   with outbuf content. */
 
+	void (*feedback)(struct ast_trans_pvt *pvt, struct ast_frame *feedback);
+	                                       /*!< Feedback frame callback. Handle 
+	                                        *   input frame. */
+
 	void (*destroy)(struct ast_trans_pvt *pvt);
 	                                       /*!< cleanup private data, if needed 
 	                                        *   (often unnecessary). */
diff -urN asterisk-14.1.2/main/channel.c asterisk-14.1.2-PATCHED/main/channel.c
--- asterisk-14.1.2/main/channel.c	2016-11-10 20:43:02.000000000 +0100
+++ asterisk-14.1.2-PATCHED/main/channel.c	2016-11-11 14:36:25.932189549 +0100
@@ -1476,6 +1476,7 @@
 	case AST_FRAME_IAX:
 	case AST_FRAME_CNG:
 	case AST_FRAME_MODEM:
+	case AST_FRAME_RTCP:
 		return 0;
 	}
 	return 0;
@@ -2832,6 +2833,7 @@
 				case AST_FRAME_IMAGE:
 				case AST_FRAME_HTML:
 				case AST_FRAME_MODEM:
+				case AST_FRAME_RTCP:
 					done = 1;
 					break;
 				case AST_FRAME_CONTROL:
@@ -4284,6 +4286,13 @@
 			 */
 			ast_read_generator_actions(chan, f);
 			break;
+		case AST_FRAME_RTCP:
+			/* Incoming RTCP feedback needs to get to the translator for
+			 * outgoing media, which means we treat it as an ast_write */
+			if(ast_channel_writetrans(chan))
+				ast_translate(ast_channel_writetrans(chan), f, 0);
+			ast_frfree(f);
+			f = &ast_null_frame;
 		default:
 			/* Just pass it on! */
 			break;
diff -urN asterisk-14.1.2/main/frame.c asterisk-14.1.2-PATCHED/main/frame.c
--- asterisk-14.1.2/main/frame.c	2016-11-10 20:43:02.000000000 +0100
+++ asterisk-14.1.2-PATCHED/main/frame.c	2016-11-11 14:36:25.930189538 +0100
@@ -535,6 +535,8 @@
 			break;
 		}
 		break;
+	case AST_FRAME_RTCP:
+		ast_copy_string(subclass, "RTCP", slen);
 	default:
 		ast_copy_string(subclass, "Unknown Subclass", slen);
 		break;
@@ -586,6 +588,9 @@
 	case AST_FRAME_VIDEO:
 		ast_copy_string(ftype, "Video", len);
 		break;
+	case AST_FRAME_RTCP:
+		ast_copy_string(ftype, "RTCP", len);
+		break;
 	default:
 		snprintf(ftype, len, "Unknown Frametype '%u'", frame_type);
 		break;
@@ -623,6 +628,9 @@
 	if (f->frametype == AST_FRAME_VIDEO) {
 		return;
 	}
+	if (f->frametype == AST_FRAME_RTCP) {
+		return;
+	}
 
 	ast_frame_type2str(f->frametype, ftype, sizeof(ftype));
 	ast_frame_subclass2str(f, subclass, sizeof(subclass), moreinfo, sizeof(moreinfo));
diff -urN asterisk-14.1.2/main/translate.c asterisk-14.1.2-PATCHED/main/translate.c
--- asterisk-14.1.2/main/translate.c	2016-11-10 20:43:02.000000000 +0100
+++ asterisk-14.1.2-PATCHED/main/translate.c	2016-11-11 14:36:25.931189544 +0100
@@ -532,6 +532,14 @@
 	long len;
 	int seqno;
 
+	if(f->frametype == AST_FRAME_RTCP) {
+		/* Just pass the feedback to the right callback, if it exists.
+		 * This "translation" does nothing so return a null frame. */
+		if(p->t->feedback)		
+			p->t->feedback(p, f);
+		return &ast_null_frame;		
+	}
+
 	has_timing_info = ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO);
 	ts = f->ts;
 	len = f->len;
diff -urN asterisk-14.1.2/res/res_rtp_asterisk.c asterisk-14.1.2-PATCHED/res/res_rtp_asterisk.c
--- asterisk-14.1.2/res/res_rtp_asterisk.c	2016-11-10 20:43:02.000000000 +0100
+++ asterisk-14.1.2-PATCHED/res/res_rtp_asterisk.c	2016-11-11 14:37:29.235508267 +0100
@@ -4236,6 +4236,28 @@
 					rtcp_report,
 					message_blob);
 			ast_json_unref(message_blob);
+
+			/* Return an AST_FRAME_RTCP frame with the ast_rtp_rtcp_report
+			 * object as a its data */
+			rtp->f.frametype = AST_FRAME_RTCP;
+			rtp->f.data.ptr = rtp->rawdata + AST_FRIENDLY_OFFSET;
+			memcpy(rtp->f.data.ptr, rtcp_report, sizeof(struct ast_rtp_rtcp_report));
+			rtp->f.datalen = sizeof(struct ast_rtp_rtcp_report);
+			if(rc > 0) {
+				/* There's always a single report block stored, here */
+				report_block = rtp->f.data.ptr + rtp->f.datalen + sizeof(struct ast_rtp_rtcp_report_block *);
+				memcpy(report_block, rtcp_report->report_block[0], sizeof(struct ast_rtp_rtcp_report_block));
+				struct ast_rtp_rtcp_report *rtcp_report2 = (struct ast_rtp_rtcp_report *)rtp->f.data.ptr;
+				rtcp_report2->report_block[0] = report_block;
+				rtp->f.datalen += sizeof(struct ast_rtp_rtcp_report_block);
+			}
+			rtp->f.offset = AST_FRIENDLY_OFFSET;
+			rtp->f.samples = 0;
+			rtp->f.mallocd = 0;
+			rtp->f.delivery.tv_sec = 0;
+			rtp->f.delivery.tv_usec = 0;
+			rtp->f.src = "RTP";
+			f = &rtp->f;
 			break;
 		case RTCP_PT_FUR:
 		/* Handle RTCP FIR as FUR */
