[svn-commits] oej: branch oej/videocaps-ng2 r99841 - in /team/oej/videocaps-ng2: apps/ chan...
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Wed Jan 23 04:57:19 CST 2008
Author: oej
Date: Wed Jan 23 04:57:18 2008
New Revision: 99841
URL: http://svn.digium.com/view/asterisk?view=rev&rev=99841
Log:
Ok, a videocaps branch that compiles - based on an old version of Asterisk trunk.
Let's see if automerge can do a bit of magic here and restore this to latest release
over lunch...
Modified:
team/oej/videocaps-ng2/apps/app_dial.c
team/oej/videocaps-ng2/channels/chan_h323.c
team/oej/videocaps-ng2/channels/chan_sip.c
team/oej/videocaps-ng2/configs/sip.conf.sample
team/oej/videocaps-ng2/formats/format_h263.c
team/oej/videocaps-ng2/include/asterisk/channel.h
team/oej/videocaps-ng2/include/asterisk/frame.h
team/oej/videocaps-ng2/include/asterisk/rtp.h
team/oej/videocaps-ng2/main/channel.c
team/oej/videocaps-ng2/main/cli.c
team/oej/videocaps-ng2/main/frame.c
team/oej/videocaps-ng2/main/rtp.c
Change Statistics:
0 files changed
Modified: team/oej/videocaps-ng2/apps/app_dial.c
URL: http://svn.digium.com/view/asterisk/team/oej/videocaps-ng2/apps/app_dial.c?view=diff&rev=99841&r1=99840&r2=99841
==============================================================================
--- team/oej/videocaps-ng2/apps/app_dial.c (original)
+++ team/oej/videocaps-ng2/apps/app_dial.c Wed Jan 23 04:57:18 2008
@@ -466,6 +466,7 @@
if (single)
ast_channel_make_compatible(o->chan, in);
ast_channel_inherit_variables(in, o->chan);
+ ast_set_capabilities(o->chan, &in->channelcaps);
} else
ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
}
@@ -709,6 +710,10 @@
case AST_CONTROL_FLASH:
/* Ignore going off hook and flash */
break;
+ case AST_CONTROL_CAPABILITY:
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "Call on %s is indicating caps %d\n", o->chan->name, f->datalen);
+ ast_indicate_data(in, AST_CONTROL_CAPABILITY, f->data, f->datalen);
case -1:
if (!ast_test_flag(outgoing, OPT_RINGBACK | OPT_MUSICBACK)) {
if (option_verbose > 2)
@@ -719,7 +724,8 @@
break;
default:
if (option_debug)
- ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
+ ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
+ ast_verbose("Dunno what to do with control type %d\n", f->subclass);
}
} else if (single) {
/* XXX are we sure the logic is correct ? or we should just switch on f->frametype ? */
@@ -795,6 +801,7 @@
if (single && (f->frametype == AST_FRAME_CONTROL) &&
((f->subclass == AST_CONTROL_HOLD) ||
(f->subclass == AST_CONTROL_UNHOLD) ||
+ (f->subclass == AST_CONTROL_CAPABILITY) ||
(f->subclass == AST_CONTROL_VIDUPDATE))) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "%s requested special control %d, passing it to %s\n", in->name, f->subclass, outgoing->chan->name);
@@ -1323,6 +1330,7 @@
free(tmp);
continue;
}
+ ast_set_capabilities(tc, &chan->channelcaps);
pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", numsubst);
if (!ast_strlen_zero(tc->call_forward)) {
char tmpchan[256];
@@ -1356,8 +1364,10 @@
}
if (!tc)
ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
- else
+ else {
ast_channel_inherit_variables(chan, tc);
+ ast_set_capabilities(tmp->chan, &chan->channelcaps);
+ }
} else {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Too many forwards from %s\n", tc->name);
Modified: team/oej/videocaps-ng2/channels/chan_h323.c
URL: http://svn.digium.com/view/asterisk/team/oej/videocaps-ng2/channels/chan_h323.c?view=diff&rev=99841&r1=99840&r2=99841
==============================================================================
--- team/oej/videocaps-ng2/channels/chan_h323.c (original)
+++ team/oej/videocaps-ng2/channels/chan_h323.c Wed Jan 23 04:57:18 2008
@@ -1938,6 +1938,7 @@
return info;
}
+#if 0
/*! \brief
* Definition taken from rtp.c for rtpPayloadType because we need it here.
*/
@@ -1945,6 +1946,7 @@
int isAstFormat; /* whether the following code is an AST_FORMAT */
int code;
};
+#endif
/*! \brief
* Call-back function passing remote ip/port information from H.323 to asterisk
Modified: team/oej/videocaps-ng2/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/oej/videocaps-ng2/channels/chan_sip.c?view=diff&rev=99841&r1=99840&r2=99841
==============================================================================
--- team/oej/videocaps-ng2/channels/chan_sip.c (original)
+++ team/oej/videocaps-ng2/channels/chan_sip.c Wed Jan 23 04:57:18 2008
@@ -1,3 +1,5 @@
+/* TIAS support seems half done...
+*/
/*
* Asterisk -- An open source telephony toolkit.
*
@@ -528,11 +530,20 @@
#define DEFAULT_QUALIFY FALSE
#define DEFAULT_REGEXTENONQUALIFY FALSE
#define DEFAULT_T1MIN 100 /*!< 100 MS for minimal roundtrip time */
-#define DEFAULT_MAX_CALL_BITRATE (384) /*!< Max bitrate for video */
+#define DEFAULT_MAX_FRAMERATE (30)
+#define VIDEO_UPDATE_XML 1
+#define VIDEO_UPDATE_RTCP 2
+#define DEFAULT_VIDEO_UPDATE (VIDEO_UPDATE_XML)
#ifndef DEFAULT_USERAGENT
#define DEFAULT_USERAGENT "Asterisk PBX" /*!< Default Useragent: header unless re-defined in sip.conf */
#endif
+static int global_videoupdate = DEFAULT_VIDEO_UPDATE;
+/* We set default caps but make them invalid.
+ If a rtpmap comes in the we set valid.
+ If a fmtp comes in then we overwrite with new values.
+ */
+static struct ast_capabilities global_caps;
/* Default setttings are used as a channel setting and as a default when
configuring devices */
@@ -547,7 +558,6 @@
static char default_mohinterpret[MAX_MUSICCLASS]; /*!< Global setting for moh class to use when put on hold */
static char default_mohsuggest[MAX_MUSICCLASS]; /*!< Global setting for moh class to suggest when putting
* a bridged channel on hold */
-static int default_maxcallbitrate; /*!< Maximum bitrate for call */
static struct ast_codec_pref default_prefs; /*!< Default codec prefs */
/* Global settings only apply to the channel */
@@ -817,6 +827,7 @@
#define SIP_PAGE2_TEXTSUPPORT (1 << 28) /*!< 28: Global text enable */
#define SIP_PAGE2_DEBUG_TEXT (1 << 29) /*!< 29: Global text debug */
#define SIP_PAGE2_OUTGOING_CALL (1 << 30) /*!< 30: Is this an outgoing call? */
+#define SIP_PAGE2_DEBUG_CAPS (1 << 31) /*!< 31: Debug Caps */
#define SIP_PAGE2_FLAGS_TO_COPY \
(SIP_PAGE2_ALLOWSUBSCRIBE | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_VIDEOSUPPORT | \
@@ -857,6 +868,7 @@
#define sipdebug ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG)
#define sipdebug_config ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONFIG)
#define sipdebug_console ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONSOLE)
+#define sipdebug_caps ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_CAPS)
#define sipdebug_text ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_TEXT)
/*! \brief T38 States for a call */
@@ -982,11 +994,14 @@
int capability; /*!< Special capability (codec) */
int jointcapability; /*!< Supported capability at both ends (codecs) */
int peercapability; /*!< Supported peer capability */
+ int videoupdate; /*!< Defines which FU mechanism RTCP or INFO is used */
+ struct ast_capabilities caps; /*!< Supported video capapbilities for this peer/user */
+ struct ast_capabilities jointcaps; /*!< Supported video capapbilities at both ends */
+ struct ast_capabilities peercaps; /*!< Video capapbilities taken from the sdp */
int prefcodec; /*!< Preferred codec (outbound only) */
int noncodeccapability; /*!< DTMF RFC2833 telephony-event */
int jointnoncodeccapability; /*!< Joint Non codec capability */
int redircodecs; /*!< Redirect codecs */
- int maxcallbitrate; /*!< Maximum Call Bitrate for Video Calls */
struct sip_proxy *outboundproxy; /*!< Outbound proxy for this dialog */
struct t38properties t38; /*!< T38 settings */
struct sockaddr_in udptlredirip; /*!< Where our T.38 UDPTL should be going if not to us */
@@ -1104,13 +1119,14 @@
struct ast_flags flags[2]; /*!< SIP_ flags */
int amaflags; /*!< AMA flags for billing */
int callingpres; /*!< Calling id presentation */
+ struct ast_capabilities caps; /*!< User capability */
int capability; /*!< Codec capability */
int inUse; /*!< Number of calls in use */
int call_limit; /*!< Limit of concurrent calls */
enum transfermodes allowtransfer; /*! SIP Refer restriction scheme */
struct ast_ha *ha; /*!< ACL setting */
struct ast_variable *chanvars; /*!< Variables to set for channel created by user */
- int maxcallbitrate; /*!< Maximum Bitrate for a video call */
+ int videoupdate /*!< Defines use of XML or RTCP for video update */;
int autoframing;
};
@@ -1153,6 +1169,7 @@
struct ast_flags flags[2]; /*!< SIP_ flags */
int expire; /*!< When to expire this peer registration */
int capability; /*!< Codec capability */
+ struct ast_capabilities caps; /*!< Codec capability */
int rtptimeout; /*!< RTP timeout */
int rtpholdtimeout; /*!< RTP Hold Timeout */
int rtpkeepalive; /*!< Send RTP packets for keepalive */
@@ -1161,7 +1178,7 @@
struct sip_proxy *outboundproxy; /*!< Outbound proxy for this peer */
struct ast_dnsmgr_entry *dnsmgr;/*!< DNS refresh manager for peer */
struct sockaddr_in addr; /*!< IP address of peer */
- int maxcallbitrate; /*!< Maximum Bitrate for a video call */
+ int videoupdate; /*!< Defines use of XML or RTCP for video update */
/* Qualification */
struct sip_pvt *call; /*!< Call pointer */
@@ -1268,6 +1285,7 @@
static int sip_answer(struct ast_channel *ast);
static struct ast_frame *sip_read(struct ast_channel *ast);
static int sip_write(struct ast_channel *ast, struct ast_frame *frame);
+static int sip_set_capabilities(struct ast_channel *ast, struct ast_capabilities *chancaps);
static int sip_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
static int sip_transfer(struct ast_channel *ast, const char *dest);
static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
@@ -1340,7 +1358,11 @@
static const char* get_sdp_iterate(int* start, struct sip_request *req, const char *name);
static const char *get_sdp(struct sip_request *req, const char *name);
static int find_sdp(struct sip_request *req);
+static int process_h2613_fmtp(const char *fmtstr, struct ast_h2613_video_cap *vidcap, unsigned int framerate);
+static int process_h264_fmtp(const char *fmtstr, struct ast_h264_video_cap *vidcap, int framerate);
static int process_sdp(struct sip_pvt *p, struct sip_request *req);
+static void ast_build_h2613_fmtp(char **buf, size_t *size, int rtp_code, struct ast_h2613_video_cap *video_cap);
+static void ast_build_h264_fmtp(char **buf, size_t *size, int rtp_code, struct ast_h264_video_cap *video_cap);
static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate,
char **m_buf, size_t *m_size, char **a_buf, size_t *a_size,
int debug, int *min_packet_size);
@@ -1611,6 +1633,7 @@
.bridge = ast_rtp_bridge,
.early_bridge = ast_rtp_early_bridge,
.send_text = sip_sendtext,
+ .set_capabilities = sip_set_capabilities,
.func_channel_read = acf_channel_read,
};
@@ -3028,8 +3051,9 @@
ast_string_field_set(dialog, context, peer->context);
dialog->rtptimeout = peer->rtptimeout;
if (peer->call_limit)
- ast_set_flag(&dialog->flags[0], SIP_CALL_LIMIT);
- dialog->maxcallbitrate = peer->maxcallbitrate;
+ ast_set_flag(&dialog->flags[0], SIP_CALL_LIMIT);
+ ast_copy_capabilities(&dialog->caps, &peer->caps);
+ dialog->videoupdate = peer->videoupdate;
return 0;
}
@@ -3129,11 +3153,15 @@
struct ast_var_t *current;
const char *referer = NULL; /* SIP referrer */
+
p = ast->tech_pvt;
if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
ast_log(LOG_WARNING, "sip_call called on %s, neither down nor reserved\n", ast->name);
return -1;
}
+
+ if(sipdebug_caps)
+ ast_verbose("SIPCALL: entering with channel->nativeformats=%08x, p->capability=%08x, p->jointcaps=%08x\n", ast->nativeformats, p->capability, p->jointcapability);
/* Check whether there is vxml_url, distinctive ring variables */
headp=&ast->varshead;
@@ -3186,6 +3214,13 @@
return res;
p->callingpres = ast->cid.cid_pres;
+ if(sipdebug_caps)
+ ast_verbose("SIPCALL: channel->nativeformats=%08x, p->capability=%08x, p->jointcaps=%08x\n", ast->nativeformats, p->capability, p->jointcapability);
+ if (ast->channelcaps.maxcallbitrate > 0 && ast->channelcaps.maxcallbitrate < p->caps.maxcallbitrate) {
+ p->caps.maxcallbitrate = ast->channelcaps.maxcallbitrate;
+ if(sipdebug_caps)
+ ast_verbose("SIPCALL: Setting sip_pvt call rate to %d for %s in sip_call()\n", p->caps.maxcallbitrate, p->username);
+ }
p->jointcapability = ast_translate_available_formats(p->capability, p->prefcodec);
p->jointnoncodeccapability = p->noncodeccapability;
@@ -3929,6 +3964,59 @@
return res;
}
+/*! \brief sip_set_capabilities: called when channel needs to have caps updated from another channel */
+/* When * is making an outgoing call, the confcaps will be set (sip_new has already been called) but
+ jointcaps and peer caps will be zero */
+/* On the REVERSE cap exchange we'll need to do a MIN(joint, chancap); */
+static int sip_set_capabilities(struct ast_channel *ast, struct ast_capabilities *chancaps)
+{
+ struct sip_pvt *p = ast->tech_pvt;
+ int res = 0;
+
+ if(sipdebug_caps)
+ {
+ ast_verbose("Calling sip_set_capabilities for %s\n", ast->name);
+
+ if (chancaps->maxcallbitrate) {
+ ast_verbose("SET_CAPABILITIES: Chancaps (%s)\n",ast->name);
+ ast_dump_caps(chancaps);
+ }
+ if (p->jointcaps.maxcallbitrate) {
+ ast_verbose("SET_CAPABILITIES: Jointcaps (%s)\n",ast->name);
+ ast_dump_caps(&p->jointcaps);
+ }
+ if (p->peercaps.maxcallbitrate) {
+ ast_verbose("SET_CAPABILITIES: Peercaps (%s)\n",ast->name);
+ ast_dump_caps(&p->peercaps);
+ }
+ if (p->caps.maxcallbitrate) {
+ ast_verbose("SET_CAPABILITIES: Caps (%s)\n",ast->name);
+ ast_dump_caps(&p->caps);
+ }
+ }
+
+ /* Jointcaps will be zero on entry for outbound calls */
+ if (ast_are_caps_zero(&p->jointcaps)) {
+ ast_copy_capabilities(&p->jointcaps, chancaps);
+ } else {
+ ast_resolve_capabilities(&p->jointcaps,&p->jointcaps, chancaps, sipdebug_caps);
+ }
+
+ if (chancaps->h264.rtpnum != 99)
+ p->jointcaps.h264.rtpnum = chancaps->h264.rtpnum;
+
+ ast_copy_capabilities(&ast->channelcaps, &p->jointcaps);
+
+ if(sipdebug_caps) {
+ if (p->jointcaps.maxcallbitrate) {
+ ast_verbose("SET_CAPABILITIES: New Jointcaps (%s)\n",ast->name);
+ ast_dump_caps(&p->jointcaps);
+ }
+ }
+
+ return res;
+}
+
/*! \brief sip_fixup: Fix up a channel: If a channel is consumed, this is called.
Basically update any ->owner links */
static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
@@ -4107,10 +4195,26 @@
break;
case AST_CONTROL_VIDUPDATE: /* Request a video frame update */
if (p->vrtp && !ast_test_flag(&p->flags[0], SIP_NOVIDEO)) {
- transmit_info_with_vidupdate(p);
- /* ast_rtcp_send_h261fur(p->vrtp); */
+ /* Can possibly send both! */
+ if ((p->videoupdate & VIDEO_UPDATE_XML) == VIDEO_UPDATE_XML)
+ transmit_info_with_vidupdate(p);
+ if ((p->videoupdate & VIDEO_UPDATE_RTCP) == VIDEO_UPDATE_RTCP)
+ ast_rtcp_send_h261fur(p->vrtp);
+ if (p->videoupdate && sipdebug)
+ ast_verbose("Sending %s FUR to %s\n", (p->videoupdate == 0) ? "none" : (p->videoupdate == VIDEO_UPDATE_XML) ? "XML" : (p->videoupdate == VIDEO_UPDATE_RTCP) ? "RTCP": "XML and RTCP", p->cid_num);
} else
res = -1;
+ break;
+ case AST_CONTROL_CAPABILITY:
+ if (datalen == sizeof(struct ast_capabilities)) {
+ ast_resolve_capabilities(&p->jointcaps, &p->jointcaps, (struct ast_capabilities*)data, sipdebug_caps);
+ p->jointcapability = p->jointcapability | (AST_FORMAT_VIDEO_MASK & ast_get_int_from_capabilities(&p->jointcaps));
+ if(sipdebug_caps) {
+ ast_verbose("SIP INDICATE: We got a new cap of (0x%08x):\n",p->jointcapability);
+ ast_dump_caps(&p->jointcaps);
+ }
+ }
+ res = -1;
break;
case -1:
res = -1;
@@ -4185,7 +4289,24 @@
/* Set the native formats for audio and merge in video */
tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | video | text;
- if (option_debug > 2) {
+
+ if (!ast_are_caps_zero(&i->jointcaps)) {
+ if (sipdebug_caps) ast_verbose("SIP NEW: Chancaps(%s) = jointcaps\n",title ? title : i->fromdomain);
+ ast_copy_capabilities(&tmp->channelcaps, &i->jointcaps);
+ } else if (!ast_are_caps_zero(&i->caps)) {
+ if (sipdebug_caps) ast_verbose("SIP NEW: Chancaps(%s) = conf caps\n",title ? title : i->fromdomain);
+ ast_copy_capabilities(&tmp->channelcaps, &i->caps);
+ } else {
+ if (sipdebug_caps) ast_verbose("SIP NEW: Chancaps(%s) = global caps\n",title ? title : i->fromdomain);
+ ast_copy_capabilities(&tmp->channelcaps, &global_caps);
+ }
+
+ if(sipdebug_caps) {
+ ast_verbose("SIP NEW: Chancaps(%s) are now\n", title ? title : i->fromdomain);
+ ast_dump_caps(&tmp->channelcaps);
+ }
+
+ if (sipdebug && option_debug > 2) {
char buf[BUFSIZ];
ast_log(LOG_DEBUG, "*** Our native formats are %s \n", ast_getformatname_multiple(buf, BUFSIZ, tmp->nativeformats));
ast_log(LOG_DEBUG, "*** Joint capabilities are %s \n", ast_getformatname_multiple(buf, BUFSIZ, i->jointcapability));
@@ -4208,7 +4329,6 @@
else
needvideo = i->jointcapability & AST_FORMAT_VIDEO_MASK; /* Inbound call */
}
-
if (i->trtp) {
if (i->prefcodec)
needtext = i->prefcodec & AST_FORMAT_TEXT_MASK; /* Outbound call */
@@ -4216,13 +4336,26 @@
needtext = i->jointcapability & AST_FORMAT_TEXT_MASK; /* Inbound call */
}
- if (option_debug > 2) {
+ if (i->trtp) {
+ if (i->prefcodec)
+ needtext = i->prefcodec & AST_FORMAT_TEXT_MASK; /* Outbound call */
+ else
+ needtext = i->jointcapability & AST_FORMAT_TEXT_MASK; /* Inbound call */
+ }
+
+ if (sipdebug &&option_debug > 2) {
if (needvideo)
ast_log(LOG_DEBUG, "This channel can handle video! HOLLYWOOD next!\n");
else
ast_log(LOG_DEBUG, "This channel will not be able to handle video.\n");
}
+ if (sipdebug) {
+ if (needtext)
+ ast_log(LOG_DEBUG, "This channel can handle text! Shakespeare next!\n");
+ else
+ ast_log(LOG_DEBUG, "This channel will not be able to handle text.\n");
+ }
if (ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) {
@@ -4687,7 +4820,8 @@
}
if (p->udptl)
ast_udptl_setqos(p->udptl, global_tos_audio, global_cos_audio);
- p->maxcallbitrate = default_maxcallbitrate;
+ p->videoupdate = global_videoupdate;
+ ast_copy_capabilities(&p->caps, &global_caps);
}
if (useglobal_nat && sin) {
@@ -4708,6 +4842,7 @@
ast_string_field_set(p, mohinterpret, default_mohinterpret);
ast_string_field_set(p, mohsuggest, default_mohsuggest);
p->capability = global_capability;
+ ast_set_capabilities_from_int(&p->caps, p->capability);
p->allowtransfer = global_allowtransfer;
if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) ||
(ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
@@ -5125,6 +5260,159 @@
return 0;
}
+/* Returns bitrate if found else -1 */
+static int process_h2613_fmtp(const char *fmtstr, struct ast_h2613_video_cap *vidcap, unsigned int framerate)
+{
+ char *parse, *loop_str, *equals, *value_str;
+ char *sep = " ;:/,";
+ int len;
+ int i;
+ unsigned int tmp;
+ int found=0;
+
+ memset(vidcap, 0, sizeof(struct ast_h2613_video_cap));
+
+ parse = ast_strdupa(fmtstr);
+ /* Get the fmtp: and payload type out of the way */
+ for ((loop_str = strsep(&parse, sep)); loop_str; (loop_str = strsep(&parse, sep)) != NULL) {
+ if((equals = strchr(loop_str, '='))==NULL)
+ return -1;
+ found = 0;
+ len = equals - loop_str;
+ value_str = loop_str+len+1;
+ if (!strncasecmp(loop_str, "maxbr", len)){
+ if(sscanf(value_str, "%d", &tmp)) {
+ found = 1;
+ vidcap->maxbr = tmp*100; /* Convert from *100 to *1 */
+ vidcap->valid = 1;
+ /* ast_verbose("MaxBR=%d\n", vidcap->maxbr); */
+ }
+ else
+ ast_verbose("Failed to parse maxbr in process_h261_h261_fmtp()\n");
+ } else if (len == 1 && loop_str[0] >= 'A' && loop_str[0] <= 'Z') { /* this is an annex */
+ vidcap->annexes |= (1 << (loop_str[0] - 'A'));
+ found = 1;
+ ast_verbose("Found annex %c, we now have %08x\n", loop_str[0], vidcap->annexes);
+ } else { /* Check video sizes */
+ for (i = 0; i < MAX_VIDEO_SIZES; i++) {
+ if (strlen(videoSizes[i].type) == len && !strncasecmp(loop_str, videoSizes[i].type, len)) {
+ if (sscanf(value_str, "%d", &tmp)){
+ found = 1;
+ vidcap->maxfr[i] = framerate < (30 / tmp) ? framerate : (30 /tmp);
+ vidcap->valid = 1;
+ }
+ /* ast_verbose("%s->FR=%d, len=%d, string=%s\n", videoSizes[i].type, vidcap->maxfr[i], len, loop_str); */
+ }
+ }
+ }
+ if (!found)
+ ast_verbose("Unable to parse %s in fmtp\n", loop_str);
+ }
+
+ if (vidcap->valid && vidcap->maxbr)
+ return vidcap->maxbr;
+ else
+ return -1;
+}
+
+/* Returns 0 on success else -1 */
+static int process_h264_fmtp(const char *fmtstr, struct ast_h264_video_cap *vidcap, int framerate)
+{
+ char *parse, *loop_str, *equals, *value_str;
+ char *sep = " ;:/,";
+ int len;
+ struct videoSize myVideoSizes[MAX_VIDEO_SIZES];
+ int found=0;
+ int maxbr = 0;
+ int level_maxbr = 0;
+ int maxmbps = 0;
+ int level_maxmbps = 0;
+ int profile = 0;
+ int level = 0;
+ int constraint = 0;
+ int packetmode = 0;
+
+ /* "a=fmtp:%d profile-level-id=42800C; packetization-mode=0; max-br=384; max-mbps=7128\r\n" */
+
+ memcpy(myVideoSizes, videoSizes, sizeof(myVideoSizes));
+
+ parse = ast_strdupa(fmtstr);
+
+ /* Get the fmtp: and payload type out of the way */
+ for ((loop_str = strsep(&parse, sep)); loop_str; (loop_str = strsep(&parse, sep)) != NULL) {
+ if (loop_str[0] == '\0') {
+ loop_str++;
+ continue;
+ }
+ if((equals = strchr(loop_str, '='))==NULL)
+ return -1;
+ found = 0;
+ len = equals - loop_str;
+ value_str = loop_str+len+1;
+ /* Now check other parameters than can appear in a video fmtp */
+ if (!strncasecmp(loop_str, "max-br", len)) {
+ if(sscanf(value_str, "%d", &maxbr))
+ found = 1;
+ else
+ ast_verbose("Failed to parse max-br in process_h264_fmtp()\n");
+ } else if (!strncasecmp(loop_str, "max-mbps", len)) {
+ if(sscanf(value_str, "%d", &maxmbps))
+ found = 1;
+ else
+ ast_verbose("Failed to parse max-mbps in process_h264_fmtp()\n");
+ } else if (!strncasecmp(loop_str, "profile-level-id", len)) {
+ if(sscanf(value_str, "%02x%02x%02x", &profile, &constraint, &level))
+ found = 1;
+ else
+ ast_verbose("Failed to parse profile-level-id in process_h264_fmtp()\n");
+ } else if (!strncasecmp(loop_str, "packetization-mode", len)) {
+ if(sscanf(value_str, "%d", &packetmode))
+ found = 1;
+ else
+ ast_verbose("Failed to parse packetization-mode in process_h264_fmtp()\n");
+ }
+ if (!found)
+ ast_verbose("Unable to parse %s in fmtp\n", loop_str);
+ }
+
+ /* Work out picture sizes from supplied level */
+ switch (level) {
+ case level_1 : level_maxbr = 64000; level_maxmbps = 1485; break;
+ case level_1_1 : level_maxbr = 64000; level_maxmbps = 3000; break;
+ case level_1_2 : level_maxbr = 128000; level_maxmbps = 6000; break;
+ case level_1_3 : level_maxbr = 384000; level_maxmbps = 11880; break;
+ case level_2 : level_maxbr = 768000; level_maxmbps = 11880; break;
+ default : level_maxbr = 2000000; level_maxmbps = 11880; break;
+ }
+
+ maxbr = maxbr * 1000;
+
+ if (maxbr > level_maxbr)
+ vidcap->maxbr = maxbr;
+ else
+ vidcap->maxbr = level_maxbr;
+
+ if (maxmbps > level_maxmbps)
+ vidcap->maxmbps = maxmbps;
+ else
+ vidcap->maxmbps = level_maxmbps;
+
+ vidcap->profile = profile;
+ vidcap->level = level;
+ vidcap->constraint = constraint;
+ vidcap->valid = 1;
+
+ if (sipdebug_caps)
+ ast_verbose("SIP PROCESS SDP: H264:%02x, L:%02x, C:%02x, BR:%d, MB:%d\n",
+ vidcap->profile,
+ vidcap->level,
+ vidcap->constraint,
+ vidcap->maxbr,
+ vidcap->maxmbps);
+
+ return 0;
+}
+
/*! \brief Process SIP SDP offer, select formats and activate RTP channels
If offer is rejected, we will not change any properties of the call
Return 0 on success, a negative value on errors.
@@ -5135,6 +5423,7 @@
const char *m; /* SDP media offer */
const char *c;
const char *a;
+ const char *b;
char host[258];
int len = -1;
int portno = -1; /*!< RTP Audio port number */
@@ -5165,12 +5454,15 @@
int iterator;
int sendonly = -1;
int numberofports;
+ int ct, as, tias;
struct ast_rtp *newaudiortp, *newvideortp, *newtextrtp; /* Buffers for codec handling */
int newjointcapability; /* Negotiated capability */
int newpeercapability;
int newnoncodeccapability;
int numberofmediastreams = 0;
int debug = sip_debug_test_pvt(p);
+ struct rtpPayloadType payloadType;
+ int framerate = 30;
int found_rtpmap_codecs[32];
int last_rtpmap_codec=0;
@@ -5215,6 +5507,27 @@
return -1;
}
+
+ /* Get the b= bandwidths, this should really be performed with a notion of scope at session and media level */
+ iterator = req->sdp_start;
+ ct = as = tias = -1; /* indicates we didn't find one */
+ while ((b = get_sdp_iterate(&iterator, req, "b"))[0] != '\0') {
+ if (sscanf(b,"CT:%d", &ct) == 1) {
+ ct *= 1000;
+ p->peercaps.maxcallbitrate = ct;
+ } else if (sscanf(b,"AS:%d", &as) == 1) {
+ as *= 1000;
+ p->peercaps.maxvideobitrate = as;
+ } else
+ /* OUCH CLEAR THIS UP */
+ if (sscanf(b,"TIAS:%d", &tias) == 1);
+ else
+ ast_verbose("Unable to parse b=%s in process_sdp\n", b);
+ }
+
+ if(sipdebug_caps)
+ ast_verbose("SIP PROCESS SDP: CT=%d, AS=%d, TIAS=%d\n", ct, as, tias);
+
/* XXX This could block for a long time, and block the main thread! XXX */
hp = ast_gethostbyname(host, &audiohp);
if (!hp) {
@@ -5231,6 +5544,9 @@
if (p->vrtp)
ast_rtp_pt_clear(newvideortp); /* Must be cleared in case no m=video line exists */
+ if (p->trtp)
+ ast_rtp_pt_clear(newtextrtp); /* Must be cleared in case no m=text line exists */
+
if (p->trtp)
ast_rtp_pt_clear(newtextrtp); /* Must be cleared in case no m=text line exists */
@@ -5372,7 +5688,6 @@
}
}
-
if (p->rtp) {
if (portno > 0) {
sin.sin_port = htons(portno);
@@ -5421,11 +5736,6 @@
if (debug)
ast_verbose("Got unsupported a:fmtp in SDP offer \n");
breakout = TRUE;
- } else if (!strncasecmp(a, "framerate:", (size_t) 10)) {
- /* Video stuff: Not supported */
- if (debug)
- ast_verbose("Got unsupported a:framerate in SDP offer \n");
- breakout = TRUE;
} else if (!strncasecmp(a, "maxprate:", (size_t) 9)) {
/* Video stuff: Not supported */
if (debug)
@@ -5451,6 +5761,12 @@
} else if (!strcasecmp(a, "sendrecv")) {
if (sendonly == -1)
sendonly = 0;
+ continue;
+ } else if (!strncasecmp(a, "framerate:", (size_t) 10)) {
+ if (sscanf(a, "framerate: %u", &framerate) != 1)
+ framerate = 0;
+ if (debug)
+ ast_verbose("Found framerate %d\n", framerate);
continue;
} else if (strlen(a) > 5 && !strncasecmp(a, "ptime", 5)) {
char *tmp = strrchr(a, ':');
@@ -5490,10 +5806,27 @@
found_rtpmap_codecs[last_rtpmap_codec] = codec;
last_rtpmap_codec++;
+ /* Note: This should all be done in the context of the m= above */
/* Note: should really look at the 'freq' and '#chans' params too */
- /* Note: This should all be done in the context of the m= above */
if (!strncasecmp(mimeSubtype, "H26",3)) { /* Video */
- /* Not going to do anything here for the moment, but we will soon */
+ if (p->vrtp) {
+ ast_rtp_set_rtpmap_type(newvideortp, codec, "video", mimeSubtype, 0);
+ switch(mimeSubtype[3]) {
+ case '1' :
+ /*ast_verbose("Found a H.261 media type\n"); */
+ p->peercaps.h261.valid = 1;
+ break;
+ case '3' :
+ /* ast_verbose("Found a H.263 media type\n");*/
+ p->peercaps.h263.valid = 1;
+ break;
+ case '4' :
+ /* ast_verbose("Found a H.264 media type\n"); */
+ p->peercaps.h264.valid = 1;
+ p->peercaps.h264.rtpnum = codec;
+ break;
+ }
+ }
} else if (!strncasecmp(mimeSubtype, "T140",4)) { /* Text */
if (p->trtp) {
/* ast_verbose("Adding t140 mimeSubtype to textrtp struct\n"); */
@@ -5506,6 +5839,41 @@
}
}
+ /* Next, scan through each "a=fmtp:" line, noting each
+ */
+ /* XXX This needs to be done per media stream, since it's media stream specific */
+ iterator = req->sdp_start;
+ while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
+ if (sscanf(a, "fmtp: %u %n", &codec, &len) == 1) {
+ /* Note: This is used for codec parameters, like bitrate for
+ G722 and video formats for H263 and H264
+ See RFC2327 for an example */
+ if (p->vrtp) {
+ payloadType = ast_rtp_lookup_pt(newvideortp, codec);
+ switch(payloadType.code) {
+ case AST_FORMAT_H261:
+ a += len;
+ process_h2613_fmtp(a, &p->peercaps.h261, framerate);
+ break;
+ case AST_FORMAT_H263:
+ a += len;
+ process_h2613_fmtp(a, &p->peercaps.h263, framerate);
+ break;
+ case AST_FORMAT_H264:
+ a += len;
+ process_h264_fmtp(a, &p->peercaps.h264, framerate);
+ break;
+ default:
+ if (option_debug > 1) {
+ if (debug)
+ ast_verbose("Got unsupported a:fmtp %u in SDP offer\n", codec);
+ }
+ break;
+ }
+ }
+ }
+ }
+
if (udptlportno != -1) {
int found = 0, x;
@@ -5616,6 +5984,47 @@
ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
}
+ if(sipdebug_caps) {
+ ast_verbose("SIP PROCESS SDP: Peercaps: \n");
+ ast_dump_caps(&p->peercaps);
+ ast_verbose("SIP PROCESS SDP: Caps: \n");
+ ast_dump_caps(&p->caps);
+ }
+
+ /* The peercaps are now in. There will be videocap.valid=1 if there was an RTPMAP entry and there
+ will be codec information in the videocap if there was an fmtp. We now need to reconcile all these
+ caps... it is possible that a peer does not set CT for instance and we need to generate it */
+ /* It may be better to do this on the joint cap... rather than pollute the peercap with elements that
+ are not actually from the peer. */
+ check_set_video_bitrates(&p->peercaps, sipdebug_caps);
+
+ /* We now have a four way set of caps to resolve:
+ caps: come from the conf file
+ peercaps: come from the sdp
+ jointcaps: are the min of caps, peercaps and owner caps
+ owner->caps: are a copy of the new jointcaps */
+ ast_copy_capabilities(&p->jointcaps, &p->peercaps);
+ if(p->owner) {
+ ast_resolve_capabilities(&p->jointcaps, &p->owner->channelcaps, &p->jointcaps, sipdebug_caps);
+ if(sipdebug_caps) {
+ ast_verbose("SIP PROCESS SDP: Joint = Min(Owner, Joint)...\n");
+ ast_dump_caps(&p->jointcaps);
+ }
+ }
+ ast_resolve_capabilities(&p->jointcaps, &p->jointcaps, &p->caps, sipdebug_caps);
+ if(sipdebug_caps) {
+ ast_verbose("SIP PROCESS SDP: Joint = Min(Joint, ConfCaps)...\n");
+ ast_dump_caps(&p->jointcaps);
+ }
+ if(p->owner) {
+ ast_copy_capabilities(&p->owner->channelcaps, &p->jointcaps);
+ if(sipdebug_caps) {
+ ast_verbose("SIP PROCESS SDP: Owner = Joint...\n");
+ ast_dump_caps(&p->jointcaps);
+ ast_verbose("\n");
+ }
+ }
+
/* Now gather all of the codecs that we are asked for: */
ast_rtp_get_current_formats(newaudiortp, &peercapability, &peernoncodeccapability);
ast_rtp_get_current_formats(newvideortp, &vpeercapability, &vpeernoncodeccapability);
@@ -5626,7 +6035,7 @@
newnoncodeccapability = p->noncodeccapability & peernoncodeccapability;
- if (debug) {
+ if (sipdebug_caps) {
/* shame on whoever coded this.... */
char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ], s4[BUFSIZ], s5[BUFSIZ];
@@ -5768,6 +6177,10 @@
sip_peer_hold(p, TRUE);
}
+ /* Tell the other end of the call what our cap is */
+ /* XXX This needs to be changed to pass back the complex cap not just the simple cap */
+ ast_queue_control_data(p->owner, AST_CONTROL_CAPABILITY, &p->jointcaps, sizeof(p->jointcaps));
+
return 0;
}
@@ -6415,6 +6828,40 @@
return 0;
}
+static void ast_build_h2613_fmtp(char **buf, size_t *size, int rtp_code, struct ast_h2613_video_cap *video_cap)
+{
+ int i;
+
+ if(video_cap->valid) {
+ ast_build_string(buf, size, "a=fmtp:%d ",rtp_code);
+ for (i = 0; i < MAX_VIDEO_SIZES; i++) {
+ if (video_cap->maxfr[i] > 0)
+ ast_build_string(buf, size, "%s=%d ", videoSizes[i].type, 30/video_cap->maxfr[i]);
+ }
+ if (video_cap->maxbr > 0)
+ ast_build_string(buf, size, "maxbr=%d",video_cap->maxbr/100);
+ ast_build_string(buf, size, "\r\n");
+ } else {
+ ast_verbose("WARNING Video cap is not valid but have been asked to add fmtp\n");
+ ast_build_string(buf, size, "a=fmtp:%d;CIF=1;QCIF=1;maxbr=3840\r\n", rtp_code);
+ }
+}
+
+static void ast_build_h264_fmtp(char **buf, size_t *size, int rtp_code, struct ast_h264_video_cap *video_cap)
+{
+ /* ast_build_string(a_buf, a_size, "a=fmtp:%d profile-level-id=42800C; packetization-mode=0; max-br=384; max-mbps=10000\r\n", rtp_code); */
+
+ if(video_cap->valid) {
+ ast_build_string(buf, size, "a=fmtp:%d ",rtp_code);
+ ast_build_string(buf, size, "profile-level-id=42800C; packetization-mode=0; ");
+ if (video_cap->maxmbps > 0)
+ ast_build_string(buf, size, "max-mbps=%d; ",video_cap->maxmbps);
+ if (video_cap->maxbr > 0)
+ ast_build_string(buf, size, "max-br=%d",video_cap->maxbr/1000);
+ ast_build_string(buf, size, "\r\n");
+ }
+}
+
/*! \brief Add codec offer to SDP offer/answer body in INVITE or 200 OK */
static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate,
char **m_buf, size_t *m_size, char **a_buf, size_t *a_size,
@@ -6456,7 +6903,6 @@
}
/*! \brief Add video codec offer to SDP offer/answer body in INVITE or 200 OK */
-/* This is different to the audio one now so we can add more caps later */
static void add_vcodec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate,
char **m_buf, size_t *m_size, char **a_buf, size_t *a_size,
int debug, int *min_packet_size)
@@ -6475,7 +6921,21 @@
ast_build_string(m_buf, m_size, " %d", rtp_code);
ast_build_string(a_buf, a_size, "a=rtpmap:%d %s/%d\r\n", rtp_code,
ast_rtp_lookup_mime_subtype(1, codec, 0), sample_rate);
- /* Add fmtp code here */
+ if (codec == AST_FORMAT_H261) {
+ if (sipdebug_caps)
+ ast_verbose("Adding h261 fmtp\n");
+ ast_build_h2613_fmtp(a_buf, a_size, rtp_code, (struct ast_h2613_video_cap*)&p->jointcaps.h261);
+ } else if (codec == AST_FORMAT_H263) {
+ if (sipdebug_caps)
+ ast_verbose("Adding h263 fmtp\n");
+ ast_build_h2613_fmtp(a_buf, a_size, rtp_code, (struct ast_h2613_video_cap*)&p->jointcaps.h263);
+ } else if (codec == AST_FORMAT_H264) {
+ if (sipdebug_caps) {
+ ast_verbose("Adding h264 fmtp with rtpnum %d\n",p->jointcaps.h264.rtpnum);
+ }
+ ast_build_h264_fmtp(a_buf, a_size, rtp_code, (struct ast_h264_video_cap*)&p->jointcaps.h264);
+ }
+
}
/*! \brief Add text codec offer to SDP offer/answer body in INVITE or 200 OK */
@@ -6733,6 +7193,8 @@
int x;
int capability;
+ int videocapability=0;
+ int textcapability=0;
int needvideo = FALSE;
int needtext = FALSE;
int debug = sip_debug_test_pvt(p);
@@ -6795,10 +7257,37 @@
ast_build_string(&m_video_next, &m_video_left, "m=video %d RTP/AVP", ntohs(vdest.sin_port));
/* Build max bitrate string */
- if (p->maxcallbitrate)
- snprintf(bandwidth, sizeof(bandwidth), "b=CT:%d\r\n", p->maxcallbitrate);
+ if (p->jointcaps.maxcallbitrate)
+ snprintf(bandwidth, sizeof(bandwidth), "b=CT:%d\r\n", p->jointcaps.maxcallbitrate/1000);
+ else if (p->caps.maxcallbitrate)
+ snprintf(bandwidth, sizeof(bandwidth), "b=CT:%d\r\n", p->caps.maxcallbitrate/1000);
if (debug)
ast_verbose("Video is at %s port %d\n", ast_inet_ntoa(p->ourip), ntohs(vsin.sin_port));
+#if 0
+ /* For video, we can't negotiate video offers. Let's compare the incoming call with what we got. */
+ if (p->prefcodec) {
+ videocapability = (capability & p->prefcodec) & AST_FORMAT_VIDEO_MASK; /* Outbound call */
+
+ /*! \todo XXX We need to select one codec, not many, since there's no transcoding */
+
+ /* Now, merge this video capability into capability while removing unsupported codecs */
+ if (!videocapability) {
+ needvideo = FALSE;
+ if (sipdebug_caps)
+ ast_log(LOG_DEBUG, "** No compatible video codecs... Disabling video.\n");
+ }
+
+ /* Replace video capabilities with the new videocapability */
+ capability = (capability & AST_FORMAT_AUDIO_MASK) | (capability & AST_FORMAT_TEXT_MASK) | videocapability;
+
+ if (sipdebug_caps) {
+ char codecbuf[BUFSIZ];
+ if (videocapability)
+ ast_log(LOG_DEBUG, "** Our video codec selection is: %s \n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), videocapability));
+ ast_log(LOG_DEBUG, "** Capability now set to : %s \n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), capability));
+ }
+ }
+#endif
}
/* Check if we need text in this call */
@@ -6857,7 +7346,7 @@
/* Prefer the audio codec we were requested to use, first, no matter what
Note that p->prefcodec can include video codecs, so mask them out
*/
- if (capability & p->prefcodec) {
+ if ((capability & AST_FORMAT_AUDIO_MASK) & p->prefcodec) {
int codec = p->prefcodec & AST_FORMAT_AUDIO_MASK;
add_codec_to_sdp(p, codec, SDP_SAMPLE_RATE(codec),
@@ -6926,8 +7415,38 @@
if (option_debug > 2)
ast_log(LOG_DEBUG, "-- Done with adding codecs to SDP\n");
- if (!p->owner || !ast_internal_timing_enabled(p->owner))
- ast_build_string(&a_audio_next, &a_audio_left, "a=silenceSupp:off - - - -\r\n");
+ /* if(!p->owner || !ast_internal_timing_enabled(p->owner))
+ ast_build_string(&a_audio_next, &a_audio_left, "a=silenceSupp:off - - - -\r\n"); */
+
+ if (min_audio_packet_size)
+ ast_build_string(&a_audio_next, &a_audio_left, "a=ptime:%d\r\n", min_audio_packet_size);
+
+ /* XXX don't think you can have ptime for video */
+ if (min_video_packet_size)
+ ast_build_string(&a_video_next, &a_video_left, "a=ptime:%d\r\n", min_video_packet_size);
+
+ /* XXX don't think you can have ptime for text */
+ if (min_text_packet_size)
+ ast_build_string(&a_text_next, &a_text_left, "a=ptime:%d\r\n", min_text_packet_size);
+
+ if ((m_audio_left < 2) || (m_video_left < 2) || (m_text_left < 2) ||
+ (a_audio_left == 0) || (a_video_left == 0) || (a_text_left == 0))
+ ast_log(LOG_WARNING, "SIP SDP may be truncated due to undersized buffer!!\n");
+
+ if (p->jointcaps.maxvideobitrate > 0)
+ ast_build_string(&m_video_next, &m_video_left, "\r\nb=AS:%d", p->jointcaps.maxvideobitrate/1000);
+
+ //ast_build_string(&m_audio_next, &m_audio_left, "\r\n");
+ //if (needvideo)
+ //ast_build_string(&m_video_next, &m_video_left, "\r\n");
+ //if (needtext)
+ //ast_build_string(&m_text_next, &m_text_left, "\r\n");
+
+ len = strlen(version) + strlen(subject) + strlen(owner) + strlen(connection) + strlen(stime) + strlen(m_audio) + strlen(a_audio) + strlen(hold);
+ if (needvideo) /* only if video response is appropriate */
+ len += strlen(m_video) + strlen(a_video) + strlen(bandwidth) + strlen(hold);
+ if (needtext) /* only if text response is appropriate */
+ len += strlen(m_text) + strlen(a_text) + strlen(hold);
if (min_audio_packet_size)
ast_build_string(&a_audio_next, &a_audio_left, "a=ptime:%d\r\n", min_audio_packet_size);
@@ -7385,6 +7904,8 @@
static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init)
{
[... 732 lines stripped ...]
More information about the svn-commits
mailing list