mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-12 15:45:18 +00:00
Add pass through support for Opus and VP8; Opus format attribute negotiation
This patch adds pass through support for Opus and VP8. That includes: * Format attribute negotiation for Opus. Note that unlike some other codecs, the draft RFC specifies having spaces delimiting the attributes in addition to ';', so you have "attra=X; attrb=Y". This broke the attribute parsing in chan_sip, so a small tweak was also included in this patch for that. * A format attribute negotiation module for Opus, res_format_attr_opus * Fast picture update for VP8. Since VP8 uses a different RTCP packet number than FIR, this really is specific to VP8 at this time. Note that the format attribute negotiation in res_pjsip_sdp_rtp was written by mjordan. The rest of this patch was written completely by Lorenzo Miniero. Review: https://reviewboard.asterisk.org/r/2723/ (closes issue ASTERISK-21981) Reported by: Tzafrir Cohen patches: asterisk_opus+vp8_passthrough_20130718.patch uploaded by lminiero (License 6518) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397526 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -1168,10 +1168,25 @@ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const voi
|
||||
case AST_CONTROL_VIDUPDATE:
|
||||
media = pvt->media[SIP_MEDIA_VIDEO];
|
||||
if (media && media->rtp) {
|
||||
ao2_ref(channel->session, +1);
|
||||
/* FIXME: Only use this for VP8. Additional work would have to be done to
|
||||
* fully support other video codecs */
|
||||
struct ast_format_cap *fcap = ast_channel_nativeformats(ast);
|
||||
struct ast_format vp8;
|
||||
ast_format_set(&vp8, AST_FORMAT_VP8, 0);
|
||||
if (ast_format_cap_iscompatible(fcap, &vp8)) {
|
||||
/* FIXME Fake RTP write, this will be sent as an RTCP packet. Ideally the
|
||||
* RTP engine would provide a way to externally write/schedule RTCP
|
||||
* packets */
|
||||
struct ast_frame fr;
|
||||
fr.frametype = AST_FRAME_CONTROL;
|
||||
fr.subclass.integer = AST_CONTROL_VIDUPDATE;
|
||||
res = ast_rtp_instance_write(media->rtp, &fr);
|
||||
} else {
|
||||
ao2_ref(channel->session, +1);
|
||||
|
||||
if (ast_sip_push_task(channel->session->serializer, transmit_info_with_vidupdate, channel->session)) {
|
||||
ao2_cleanup(channel->session);
|
||||
if (ast_sip_push_task(channel->session->serializer, transmit_info_with_vidupdate, channel->session)) {
|
||||
ao2_cleanup(channel->session);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res = -1;
|
||||
|
@@ -1269,7 +1269,7 @@ static void add_dtls_to_sdp(struct ast_rtp_instance *instance, struct ast_str **
|
||||
static void start_ice(struct ast_rtp_instance *instance);
|
||||
static void add_codec_to_sdp(const struct sip_pvt *p, struct ast_format *codec,
|
||||
struct ast_str **m_buf, struct ast_str **a_buf,
|
||||
int debug, int *min_packet_size);
|
||||
int debug, int *min_packet_size, int *max_packet_size);
|
||||
static void add_noncodec_to_sdp(const struct sip_pvt *p, int format,
|
||||
struct ast_str **m_buf, struct ast_str **a_buf,
|
||||
int debug);
|
||||
@@ -7945,10 +7945,25 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
|
||||
break;
|
||||
case AST_CONTROL_VIDUPDATE: /* Request a video frame update */
|
||||
if (p->vrtp && !p->novideo) {
|
||||
transmit_info_with_vidupdate(p);
|
||||
/* ast_rtcp_send_h261fur(p->vrtp); */
|
||||
} else
|
||||
/* FIXME: Only use this for VP8. Additional work would have to be done to
|
||||
* fully support other video codecs */
|
||||
struct ast_format_cap *fcap = ast_channel_nativeformats(ast);
|
||||
struct ast_format vp8;
|
||||
ast_format_set(&vp8, AST_FORMAT_VP8, 0);
|
||||
if (ast_format_cap_iscompatible(fcap, &vp8)) {
|
||||
/* FIXME Fake RTP write, this will be sent as an RTCP packet. Ideally the
|
||||
* RTP engine would provide a way to externally write/schedule RTCP
|
||||
* packets */
|
||||
struct ast_frame fr;
|
||||
fr.frametype = AST_FRAME_CONTROL;
|
||||
fr.subclass.integer = AST_CONTROL_VIDUPDATE;
|
||||
res = ast_rtp_instance_write(p->vrtp, &fr);
|
||||
} else {
|
||||
transmit_info_with_vidupdate(p);
|
||||
}
|
||||
} else {
|
||||
res = -1;
|
||||
}
|
||||
break;
|
||||
case AST_CONTROL_T38_PARAMETERS:
|
||||
res = -1;
|
||||
@@ -11167,7 +11182,7 @@ static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_
|
||||
if (debug)
|
||||
ast_verbose("Discarded description format %s for ID %d\n", mimeSubtype, codec);
|
||||
}
|
||||
} else if (sscanf(a, "fmtp: %30u %255s", &codec, fmtp_string) == 2) {
|
||||
} else if (sscanf(a, "fmtp: %30u %255[^\t\n]", &codec, fmtp_string) == 2) {
|
||||
struct ast_format *format;
|
||||
|
||||
if ((format = ast_rtp_codecs_get_payload_format(newaudiortp, codec))) {
|
||||
@@ -11230,7 +11245,8 @@ static int process_sdp_a_video(const char *a, struct sip_pvt *p, struct ast_rtp_
|
||||
/* We have a rtpmap to handle */
|
||||
if (*last_rtpmap_codec < SDP_MAX_RTPMAP_CODECS) {
|
||||
/* Note: should really look at the '#chans' params too */
|
||||
if (!strncasecmp(mimeSubtype, "H26", 3) || !strncasecmp(mimeSubtype, "MP4", 3)) {
|
||||
if (!strncasecmp(mimeSubtype, "H26", 3) || !strncasecmp(mimeSubtype, "MP4", 3)
|
||||
|| !strncasecmp(mimeSubtype, "VP8", 3)) {
|
||||
if (!(ast_rtp_codecs_payloads_set_rtpmap_type_rate(newvideortp, NULL, codec, "video", mimeSubtype, 0, sample_rate))) {
|
||||
if (debug)
|
||||
ast_verbose("Found video description format %s for ID %d\n", mimeSubtype, codec);
|
||||
@@ -12799,7 +12815,8 @@ static void add_codec_to_sdp(const struct sip_pvt *p,
|
||||
struct ast_str **m_buf,
|
||||
struct ast_str **a_buf,
|
||||
int debug,
|
||||
int *min_packet_size)
|
||||
int *min_packet_size,
|
||||
int *max_packet_size)
|
||||
{
|
||||
int rtp_code;
|
||||
struct ast_format_list fmt;
|
||||
@@ -12821,7 +12838,12 @@ static void add_codec_to_sdp(const struct sip_pvt *p,
|
||||
} else /* I don't see how you couldn't have p->rtp, but good to check for and error out if not there like earlier code */
|
||||
return;
|
||||
ast_str_append(m_buf, 0, " %d", rtp_code);
|
||||
ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%d\r\n", rtp_code, mime, rate);
|
||||
/* Opus mandates 2 channels in rtpmap */
|
||||
if ((int)format->id == AST_FORMAT_OPUS) {
|
||||
ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%d/2\r\n", rtp_code, mime, rate);
|
||||
} else {
|
||||
ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%d\r\n", rtp_code, mime, rate);
|
||||
}
|
||||
|
||||
ast_format_sdp_generate(format, rtp_code, a_buf);
|
||||
|
||||
@@ -12852,12 +12874,22 @@ static void add_codec_to_sdp(const struct sip_pvt *p,
|
||||
break;
|
||||
}
|
||||
|
||||
if (fmt.cur_ms && (fmt.cur_ms < *min_packet_size))
|
||||
if (max_packet_size && fmt.max_ms && (fmt.max_ms < *max_packet_size)) {
|
||||
*max_packet_size = fmt.max_ms;
|
||||
}
|
||||
|
||||
if (fmt.cur_ms && (fmt.cur_ms < *min_packet_size)) {
|
||||
*min_packet_size = fmt.cur_ms;
|
||||
}
|
||||
|
||||
/* Our first codec packetization processed cannot be zero */
|
||||
if ((*min_packet_size)==0 && fmt.cur_ms)
|
||||
if ((*min_packet_size) == 0 && fmt.cur_ms) {
|
||||
*min_packet_size = fmt.cur_ms;
|
||||
}
|
||||
|
||||
if ((*max_packet_size) == 0 && fmt.max_ms) {
|
||||
*max_packet_size = fmt.max_ms;
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Add video codec offer to SDP offer/answer body in INVITE or 200 OK */
|
||||
@@ -12884,6 +12916,10 @@ static void add_vcodec_to_sdp(const struct sip_pvt *p, struct ast_format *format
|
||||
|
||||
ast_str_append(m_buf, 0, " %d", rtp_code);
|
||||
ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%d\r\n", rtp_code, subtype, rate);
|
||||
/* VP8: add RTCP FIR support */
|
||||
if ((int)format->id == AST_FORMAT_VP8) {
|
||||
ast_str_append(a_buf, 0, "a=rtcp-fb:* ccm fir\r\n");
|
||||
}
|
||||
|
||||
ast_format_sdp_generate(format, rtp_code, a_buf);
|
||||
}
|
||||
@@ -13128,6 +13164,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
|
||||
int needtext = FALSE;
|
||||
int debug = sip_debug_test_pvt(p);
|
||||
int min_audio_packet_size = 0;
|
||||
int max_audio_packet_size = 0;
|
||||
int min_video_packet_size = 0;
|
||||
int min_text_packet_size = 0;
|
||||
|
||||
@@ -13309,7 +13346,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
|
||||
if (AST_FORMAT_GET_TYPE(tmp_fmt.id) != AST_FORMAT_TYPE_AUDIO) {
|
||||
continue;
|
||||
}
|
||||
add_codec_to_sdp(p, &tmp_fmt, &m_audio, &a_audio, debug, &min_audio_packet_size);
|
||||
add_codec_to_sdp(p, &tmp_fmt, &m_audio, &a_audio, debug, &min_audio_packet_size, &max_audio_packet_size);
|
||||
ast_format_cap_add(alreadysent, &tmp_fmt);
|
||||
}
|
||||
ast_format_cap_iter_end(p->prefcaps);
|
||||
@@ -13329,7 +13366,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
|
||||
continue;
|
||||
|
||||
if (AST_FORMAT_GET_TYPE(tmp_fmt.id) == AST_FORMAT_TYPE_AUDIO) {
|
||||
add_codec_to_sdp(p, &tmp_fmt, &m_audio, &a_audio, debug, &min_audio_packet_size);
|
||||
add_codec_to_sdp(p, &tmp_fmt, &m_audio, &a_audio, debug, &min_audio_packet_size, &max_audio_packet_size);
|
||||
} else if (needvideo && (AST_FORMAT_GET_TYPE(tmp_fmt.id) == AST_FORMAT_TYPE_VIDEO)) {
|
||||
add_vcodec_to_sdp(p, &tmp_fmt, &m_video, &a_video, debug, &min_video_packet_size);
|
||||
} else if (needtext && (AST_FORMAT_GET_TYPE(tmp_fmt.id) == AST_FORMAT_TYPE_TEXT)) {
|
||||
@@ -13346,7 +13383,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
|
||||
continue;
|
||||
|
||||
if (AST_FORMAT_GET_TYPE(tmp_fmt.id) == AST_FORMAT_TYPE_AUDIO) {
|
||||
add_codec_to_sdp(p, &tmp_fmt, &m_audio, &a_audio, debug, &min_audio_packet_size);
|
||||
add_codec_to_sdp(p, &tmp_fmt, &m_audio, &a_audio, debug, &min_audio_packet_size, &max_audio_packet_size);
|
||||
} else if (needvideo && (AST_FORMAT_GET_TYPE(tmp_fmt.id) == AST_FORMAT_TYPE_VIDEO)) {
|
||||
add_vcodec_to_sdp(p, &tmp_fmt, &m_video, &a_video, debug, &min_video_packet_size);
|
||||
} else if (needtext && (AST_FORMAT_GET_TYPE(tmp_fmt.id) == AST_FORMAT_TYPE_TEXT)) {
|
||||
@@ -13365,19 +13402,27 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
|
||||
|
||||
ast_debug(3, "-- Done with adding codecs to SDP\n");
|
||||
|
||||
if (!p->owner || !ast_internal_timing_enabled(p->owner))
|
||||
if (!p->owner || !ast_internal_timing_enabled(p->owner)) {
|
||||
ast_str_append(&a_audio, 0, "a=silenceSupp:off - - - -\r\n");
|
||||
}
|
||||
|
||||
if (min_audio_packet_size)
|
||||
if (min_audio_packet_size) {
|
||||
ast_str_append(&a_audio, 0, "a=ptime:%d\r\n", min_audio_packet_size);
|
||||
}
|
||||
|
||||
/* XXX don't think you can have ptime for video */
|
||||
if (min_video_packet_size)
|
||||
if (min_video_packet_size) {
|
||||
ast_str_append(&a_video, 0, "a=ptime:%d\r\n", min_video_packet_size);
|
||||
}
|
||||
|
||||
/* XXX don't think you can have ptime for text */
|
||||
if (min_text_packet_size)
|
||||
if (min_text_packet_size) {
|
||||
ast_str_append(&a_text, 0, "a=ptime:%d\r\n", min_text_packet_size);
|
||||
}
|
||||
|
||||
if (max_audio_packet_size) {
|
||||
ast_str_append(&a_text, 0, "a=maxptime:%d\r\n", max_audio_packet_size);
|
||||
}
|
||||
|
||||
if (!doing_directmedia) {
|
||||
if (ast_test_flag(&p->flags[2], SIP_PAGE3_ICE_SUPPORT)) {
|
||||
|
Reference in New Issue
Block a user