diff --git a/app.c b/app.c index f3a84c3a59f4d76760337f430071d6dc42376dac..4db43846b3a63170e62adb7c3f1956c6547d4693 100755 --- a/app.c +++ b/app.c @@ -615,6 +615,8 @@ int ast_play_and_record(struct ast_channel *chan, const char *playfile, const ch return -1; } } + /* Request a video update */ + ast_indicate(chan, AST_CONTROL_VIDUPDATE); if (x == fmtcnt) { /* Loop forever, writing the packets we read to the writer(s), until diff --git a/apps/app_dial.c b/apps/app_dial.c index 8fe9fc43ad562ddcf7dbc1b92fef2426021e8382..ca72060b9ea9b26efbf763fa64007357bc3a1588 100755 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -493,6 +493,11 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu if (!ast_test_flag(outgoing, DIAL_RINGBACKONLY)) ast_indicate(in, AST_CONTROL_PROGRESS); break; + case AST_CONTROL_VIDUPDATE: + if (option_verbose > 2) + ast_verbose ( VERBOSE_PREFIX_3 "%s requested a video update, passing it to %s\n", o->chan->name,in->name); + ast_indicate(in, AST_CONTROL_VIDUPDATE); + break; case AST_CONTROL_PROCEEDING: if (option_verbose > 2) ast_verbose ( VERBOSE_PREFIX_3 "%s is proceeding passing it to %s\n", o->chan->name,in->name); @@ -600,6 +605,11 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu if (ast_write(outgoing->chan, f)) ast_log(LOG_WARNING, "Unable to forward voice\n"); } + if (single && (f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_VIDUPDATE)) { + if (option_verbose > 2) + ast_verbose ( VERBOSE_PREFIX_3 "%s requested a video update, passing it to %s\n", in->name,outgoing->chan->name); + ast_indicate(outgoing->chan, AST_CONTROL_VIDUPDATE); + } ast_frfree(f); } if (!*to && (option_verbose > 2)) diff --git a/apps/app_record.c b/apps/app_record.c index c5da8f91027d7bfcd2f3446ed700b664a4506473..bb0e1ed0007a4ad2423847c8f40a6fb6872fb768 100755 --- a/apps/app_record.c +++ b/apps/app_record.c @@ -218,6 +218,9 @@ static int record_exec(struct ast_channel *chan, void *data) if (s) { + /* Request a video update */ + ast_indicate(chan, AST_CONTROL_VIDUPDATE); + if (maxduration > 0) timeout = time(NULL) + (time_t)maxduration; diff --git a/channel.c b/channel.c index 6fd536b7f0fe345e18c666e83d394f837a01962e..282a7967e90288c2bc33c6d17b77e26c96a893e2 100755 --- a/channel.c +++ b/channel.c @@ -1721,6 +1721,8 @@ int ast_indicate(struct ast_channel *chan, int condition) /* Do nothing.... */ } else if (condition == AST_CONTROL_UNHOLD) { /* Do nothing.... */ + } else if (condition == AST_CONTROL_VIDUPDATE) { + /* Do nothing.... */ } else { /* not handled */ ast_log(LOG_WARNING, "Unable to handle indication %d for '%s'\n", condition, chan->name); @@ -2966,7 +2968,8 @@ static enum ast_bridge_result ast_generic_bridge(int *playitagain, int *playit, } if ((f->frametype == AST_FRAME_CONTROL) && !(config->flags & AST_BRIDGE_IGNORE_SIGS)) { - if ((f->subclass == AST_CONTROL_HOLD) || (f->subclass == AST_CONTROL_UNHOLD)) { + if ((f->subclass == AST_CONTROL_HOLD) || (f->subclass == AST_CONTROL_UNHOLD) || + (f->subclass == AST_CONTROL_VIDUPDATE)) { ast_indicate(who == c0 ? c1 : c0, f->subclass); } else { *fo = f; diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 0b77fabc4a50dc1f43f7859eee7861ab954c4ae4..bdd2c36e88c1ab0b54af65f0765d896314d4924d 100755 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -832,6 +832,7 @@ static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, int inc, static int transmit_invite(struct sip_pvt *p, int sipmethod, int sendsdp, struct sip_invite_param *options, int init); static int transmit_reinvite_with_sdp(struct sip_pvt *p); static int transmit_info_with_digit(struct sip_pvt *p, char digit); +static int transmit_info_with_vidupdate(struct sip_pvt *p); static int transmit_message_with_text(struct sip_pvt *p, const char *text); static int transmit_refer(struct sip_pvt *p, const char *dest); static int sip_sipredirect(struct sip_pvt *p, const char *dest); @@ -2609,6 +2610,13 @@ static int sip_indicate(struct ast_channel *ast, int condition) ast_log(LOG_DEBUG, "Bridged channel is back from hold, let's talk! : %s\n", p->callid); res = -1; break; + case AST_CONTROL_VIDUPDATE: /* Request a video frame update */ + if (p->vrtp && !ast_test_flag(p, SIP_NOVIDEO)) { + transmit_info_with_vidupdate(p); + res = 0; + } else + res = -1; + break; case -1: res = -1; break; @@ -3949,7 +3957,7 @@ static int __transmit_response(struct sip_pvt *p, char *msg, struct sip_request /* If we are cancelling an incoming invite for some reason, add information about the reason why we are doing this in clear text */ if (p->owner && p->owner->hangupcause) { - add_header(&resp, "X-Asterisk-HangupCause:", ast_cause2str(p->owner->hangupcause)); + add_header(&resp, "X-Asterisk-HangupCause", ast_cause2str(p->owner->hangupcause)); } add_blank_header(&resp); return send_response(p, &resp, reliable, seqno); @@ -4056,6 +4064,26 @@ static int add_digit(struct sip_request *req, char digit) return 0; } +/*--- add_vidupdate: add XML encoded media control with update ---*/ +/* XML: The only way to turn 0 bits of information into a few hundred. */ +static int add_vidupdate(struct sip_request *req) +{ + const char *xml_is_a_huge_waste_of_space = + "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n" + " <media_control>\r\n" + " <vc_primitive>\r\n" + " <to_encoder>\r\n" + " <picture_fast_update\r\n" + " </picture_fast_update>\r\n" + " </to_encoder>\r\n" + " </vc_primitive>\r\n" + " </media_control>\r\n"; + add_header(req, "Content-Type", "application/media_control+xml"); + add_header_contentLength(req, strlen(xml_is_a_huge_waste_of_space)); + add_line(req, xml_is_a_huge_waste_of_space); + return 0; +} + /*--- add_sdp: Add Session Description Protocol message ---*/ static int add_sdp(struct sip_request *resp, struct sip_pvt *p) { @@ -5209,6 +5237,15 @@ static int transmit_info_with_digit(struct sip_pvt *p, char digit) return send_request(p, &req, 1, p->ocseq); } +/*--- transmit_info_with_vidupdate: Send SIP INFO with video update request ---*/ +static int transmit_info_with_vidupdate(struct sip_pvt *p) +{ + struct sip_request req; + reqprep(&req, p, SIP_INFO, 0, 1); + add_vidupdate(&req); + return send_request(p, &req, 1, p->ocseq); +} + /*--- transmit_request: transmit generic SIP request ---*/ static int transmit_request(struct sip_pvt *p, int sipmethod, int seqno, int reliable, int newbranch) { @@ -8125,6 +8162,12 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req) ast_set_flag(p, SIP_NEEDDESTROY); } return; + } else if (!strcasecmp(get_header(req, "Content-Type"), "application/media_control+xml")) { + /* Eh, we'll just assume it's a fast picture update for now */ + if (p->owner) + ast_queue_control(p->owner, AST_CONTROL_VIDUPDATE); + transmit_response(p, "200 OK", req); + return; } else if ((c = get_header(req, "X-ClientCode"))) { /* Client code (from SNOM phone) */ if (ast_test_flag(p, SIP_USECLIENTCODE)) { diff --git a/file.c b/file.c index 6fcd31173f6d2074b6f896dd11954f50a4449059..ab24719cbb920268a8d7dcdc976de65f3559ac4d 100755 --- a/file.c +++ b/file.c @@ -987,6 +987,7 @@ int ast_waitstream(struct ast_channel *c, const char *breakon) return -1; case AST_CONTROL_RINGING: case AST_CONTROL_ANSWER: + case AST_CONTROL_VIDUPDATE: /* Unimportant */ break; default: diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index 41a4e7cb5f172f9c5ec8110d2a251947d38ecf21..364aaa4cc55d95750405bb9ce3116cbaa52758fb 100755 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -194,6 +194,8 @@ struct ast_frame_chain { #define AST_CONTROL_HOLD 16 /*! Indicate call is left from hold */ #define AST_CONTROL_UNHOLD 17 +/*! Indicate video frame update */ +#define AST_CONTROL_VIDUPDATE 18 #define AST_SMOOTHER_FLAG_G729 (1 << 0) diff --git a/rtp.c b/rtp.c index 71a24360f7892e5c9c46e07aebf79bb1eb41895c..e71b2e0223a6368c6663aad20e71265eb6218102 100755 --- a/rtp.c +++ b/rtp.c @@ -672,7 +672,7 @@ void ast_rtp_pt_default(struct ast_rtp* rtp) rtp->rtp_lookup_code_cache_result = 0; } -/* Make a note of a RTP payload type that was seen in a SDP "m=" line. */ +/* Make a note of a RTP paymoad type that was seen in a SDP "m=" line. */ /* By default, use the well-known value for this type (although it may */ /* still be set to a different value by a subsequent "a=rtpmap:" line): */ void ast_rtp_set_m_type(struct ast_rtp* rtp, int pt) { @@ -1628,6 +1628,17 @@ enum ast_bridge_result ast_rtp_bridge(struct ast_channel *c0, struct ast_channel ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name); } return AST_BRIDGE_COMPLETE; + } else if ((f->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) { + if ((f->subclass == AST_CONTROL_HOLD) || (f->subclass == AST_CONTROL_UNHOLD) || + (f->subclass == AST_CONTROL_VIDUPDATE)) { + ast_indicate(who == c0 ? c1 : c0, f->subclass); + ast_frfree(f); + } else { + *fo = f; + *rc = who; + ast_log(LOG_DEBUG, "Got a FRAME_CONTROL (%d) frame on channel %s\n", f->subclass, who->name); + return AST_BRIDGE_COMPLETE; + } } else { if ((f->frametype == AST_FRAME_DTMF) || (f->frametype == AST_FRAME_VOICE) ||