[svn-commits] mjordan: branch mjordan/12-channel-func r403239 - in /team/mjordan/12-channel...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Fri Nov 29 22:02:40 CST 2013


Author: mjordan
Date: Fri Nov 29 22:02:38 2013
New Revision: 403239

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=403239
Log:
Actually *add* the database schema management utilities

In r397874, the scripts were removed... but not replaced. Thanks to
Michael Young for noticing this!

Added:
    team/mjordan/12-channel-func/channels/pjsip/
    team/mjordan/12-channel-func/channels/pjsip/dialplan_functions.c   (with props)
    team/mjordan/12-channel-func/channels/pjsip/include/
    team/mjordan/12-channel-func/channels/pjsip/include/chan_pjsip.h   (with props)
    team/mjordan/12-channel-func/channels/pjsip/include/dialplan_functions.h   (with props)
    team/mjordan/12-channel-func/doc/appdocsxml.xslt   (with props)
    team/mjordan/12-channel-func/funcs/func_pjsip_endpoint.c   (with props)
Removed:
    team/mjordan/12-channel-func/doc/snapshots.xslt
Modified:
    team/mjordan/12-channel-func/Makefile
    team/mjordan/12-channel-func/channels/Makefile
    team/mjordan/12-channel-func/channels/chan_pjsip.c
    team/mjordan/12-channel-func/doc/appdocsxml.dtd
    team/mjordan/12-channel-func/funcs/func_channel.c
    team/mjordan/12-channel-func/main/sorcery.c
    team/mjordan/12-channel-func/main/xmldoc.c

Modified: team/mjordan/12-channel-func/Makefile
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/12-channel-func/Makefile?view=diff&rev=403239&r1=403238&r2=403239
==============================================================================
--- team/mjordan/12-channel-func/Makefile (original)
+++ team/mjordan/12-channel-func/Makefile Fri Nov 29 22:02:38 2013
@@ -448,7 +448,7 @@
 		fi \
 	done
 	$(INSTALL) -m 644 doc/core-en_US.xml "$(DESTDIR)$(ASTDATADIR)/static-http";
-	$(INSTALL) -m 644 doc/snapshots.xslt "$(DESTDIR)$(ASTDATADIR)/static-http";
+	$(INSTALL) -m 644 doc/appdocsxml.xslt "$(DESTDIR)$(ASTDATADIR)/static-http";
 	if [ -d doc/tex/asterisk ] ; then \
 		$(INSTALL) -d "$(DESTDIR)$(ASTDATADIR)/static-http/docs" ; \
 		for n in doc/tex/asterisk/* ; do \
@@ -471,7 +471,7 @@
 	@printf "Building Documentation For: "
 	@echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" > $@
 	@echo "<!DOCTYPE docs SYSTEM \"appdocsxml.dtd\">" >> $@
-	@echo "<?xml-stylesheet type=\"text/xsl\" href=\"snapshots.xslt\"?>" > $@
+	@echo "<?xml-stylesheet type=\"text/xsl\" href=\"appdocsxml.xslt\"?>" > $@
 	@echo "<docs xmlns:xi=\"http://www.w3.org/2001/XInclude\">" >> $@
 	@for x in $(MOD_SUBDIRS); do \
 		printf "$$x " ; \
@@ -495,7 +495,7 @@
 	@printf "Building Documentation For: "
 	@echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" > $@
 	@echo "<!DOCTYPE docs SYSTEM \"appdocsxml.dtd\">" >> $@
-	@echo "<?xml-stylesheet type=\"text/xsl\" href=\"snapshots.xslt\"?>" > $@
+	@echo "<?xml-stylesheet type=\"text/xsl\" href=\"appdocsxml.xslt\"?>" > $@
 	@echo "<docs xmlns:xi=\"http://www.w3.org/2001/XInclude\">" >> $@
 	@for x in $(MOD_SUBDIRS); do \
 		printf "$$x " ; \
@@ -578,7 +578,7 @@
 	fi
 
 	$(INSTALL) -m 644 doc/core-*.xml "$(DESTDIR)$(ASTDATADIR)/documentation"
-	$(INSTALL) -m 644 doc/snapshots.xslt "$(DESTDIR)$(ASTDATADIR)/documentation"
+	$(INSTALL) -m 644 doc/appdocsxml.xslt "$(DESTDIR)$(ASTDATADIR)/documentation"
 	$(INSTALL) -m 644 doc/appdocsxml.dtd "$(DESTDIR)$(ASTDATADIR)/documentation"
 	$(INSTALL) -m 644 doc/asterisk.8 "$(DESTDIR)$(ASTMANDIR)/man8"
 	$(INSTALL) -m 644 doc/astdb*.8 "$(DESTDIR)$(ASTMANDIR)/man8"

Modified: team/mjordan/12-channel-func/channels/Makefile
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/12-channel-func/channels/Makefile?view=diff&rev=403239&r1=403238&r2=403239
==============================================================================
--- team/mjordan/12-channel-func/channels/Makefile (original)
+++ team/mjordan/12-channel-func/channels/Makefile Fri Nov 29 22:02:38 2013
@@ -77,6 +77,9 @@
 $(if $(filter chan_sip,$(EMBEDDED_MODS)),modules.link,chan_sip.so): $(subst .c,.o,$(wildcard sip/*.c))
 $(subst .c,.o,$(wildcard sip/*.c)): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,chan_sip)
 
+$(if $(filter chan_pjsip,$(EMBEDDED_MODS)),modules.link,chan_pjsip.so): $(subst .c,.o,$(wildcard pjsip/*.c))
+$(subst .c,.o,$(wildcard pjsip/*.c)): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,chan_pjsip)
+
 # Additional objects to combine with chan_dahdi.so
 CHAN_DAHDI_OBJS= \
 	$(subst .c,.o,$(wildcard dahdi/*.c))	\

Modified: team/mjordan/12-channel-func/channels/chan_pjsip.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/12-channel-func/channels/chan_pjsip.c?view=diff&rev=403239&r1=403238&r2=403239
==============================================================================
--- team/mjordan/12-channel-func/channels/chan_pjsip.c (original)
+++ team/mjordan/12-channel-func/channels/chan_pjsip.c Fri Nov 29 22:02:38 2013
@@ -61,61 +61,13 @@
 #include "asterisk/res_pjsip.h"
 #include "asterisk/res_pjsip_session.h"
 
-/*** DOCUMENTATION
-	<function name="PJSIP_DIAL_CONTACTS" language="en_US">
-		<synopsis>
-			Return a dial string for dialing all contacts on an AOR.
-		</synopsis>
-		<syntax>
-			<parameter name="endpoint" required="true">
-				<para>Name of the endpoint</para>
-			</parameter>
-			<parameter name="aor" required="false">
-				<para>Name of an AOR to use, if not specified the configured AORs on the endpoint are used</para>
-			</parameter>
-			<parameter name="request_user" required="false">
-				<para>Optional request user to use in the request URI</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Returns a properly formatted dial string for dialing all contacts on an AOR.</para>
-		</description>
-	</function>
-	<function name="PJSIP_MEDIA_OFFER" language="en_US">
-		<synopsis>
-			Media and codec offerings to be set on an outbound SIP channel prior to dialing.
-		</synopsis>
-		<syntax>
-			<parameter name="media" required="true">
-				<para>types of media offered</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Returns the codecs offered based upon the media choice</para>
-		</description>
-	</function>
- ***/
+#include "pjsip/include/chan_pjsip.h"
+#include "pjsip/include/dialplan_functions.h"
 
 static const char desc[] = "PJSIP Channel";
 static const char channel_type[] = "PJSIP";
 
 static unsigned int chan_idx;
-
-/*!
- * \brief Positions of various media
- */
-enum sip_session_media_position {
-	/*! \brief First is audio */
-	SIP_MEDIA_AUDIO = 0,
-	/*! \brief Second is video */
-	SIP_MEDIA_VIDEO,
-	/*! \brief Last is the size for media details */
-	SIP_MEDIA_SIZE,
-};
-
-struct chan_pjsip_pvt {
-	struct ast_sip_session_media *media[SIP_MEDIA_SIZE];
-};
 
 static void chan_pjsip_pvt_dtor(void *obj)
 {
@@ -145,7 +97,7 @@
 static int chan_pjsip_queryoption(struct ast_channel *ast, int option, void *data, int *datalen);
 
 /*! \brief PBX interface structure for channel registration */
-static struct ast_channel_tech chan_pjsip_tech = {
+struct ast_channel_tech chan_pjsip_tech = {
 	.type = channel_type,
 	.description = "PJSIP Channel Driver",
 	.requester = chan_pjsip_request,
@@ -164,6 +116,7 @@
 	.fixup = chan_pjsip_fixup,
 	.devicestate = chan_pjsip_devicestate,
 	.queryoption = chan_pjsip_queryoption,
+	.func_channel_read = pjsip_acf_channel_read,
 	.properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
 };
 
@@ -189,184 +142,6 @@
 	.method = "ACK",
 	.priority = AST_SIP_SESSION_SUPPLEMENT_PRIORITY_CHANNEL,
 	.incoming_request = chan_pjsip_incoming_ack,
-};
-
-/*! \brief Dialplan function for constructing a dial string for calling all contacts */
-static int chan_pjsip_dial_contacts(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
-{
-	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_str *, dial, NULL, ast_free_ptr);
-	const char *aor_name;
-	char *rest;
-
-	AST_DECLARE_APP_ARGS(args,
-		AST_APP_ARG(endpoint_name);
-		AST_APP_ARG(aor_name);
-		AST_APP_ARG(request_user);
-	);
-
-	AST_STANDARD_APP_ARGS(args, data);
-
-	if (ast_strlen_zero(args.endpoint_name)) {
-		ast_log(LOG_WARNING, "An endpoint name must be specified when using the '%s' dialplan function\n", cmd);
-		return -1;
-	} else if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", args.endpoint_name))) {
-		ast_log(LOG_WARNING, "Specified endpoint '%s' was not found\n", args.endpoint_name);
-		return -1;
-	}
-
-	aor_name = S_OR(args.aor_name, endpoint->aors);
-
-	if (ast_strlen_zero(aor_name)) {
-		ast_log(LOG_WARNING, "No AOR has been provided and no AORs are configured on endpoint '%s'\n", args.endpoint_name);
-		return -1;
-	} else if (!(dial = ast_str_create(len))) {
-		ast_log(LOG_WARNING, "Could not get enough buffer space for dialing contacts\n");
-		return -1;
-	} else if (!(rest = ast_strdupa(aor_name))) {
-		ast_log(LOG_WARNING, "Could not duplicate provided AORs\n");
-		return -1;
-	}
-
-	while ((aor_name = strsep(&rest, ","))) {
-		RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup);
-		RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
-		struct ao2_iterator it_contacts;
-		struct ast_sip_contact *contact;
-
-		if (!aor) {
-			/* If the AOR provided is not found skip it, there may be more */
-			continue;
-		} else if (!(contacts = ast_sip_location_retrieve_aor_contacts(aor))) {
-			/* No contacts are available, skip it as well */
-			continue;
-		} else if (!ao2_container_count(contacts)) {
-			/* We were given a container but no contacts are in it... */
-			continue;
-		}
-
-		it_contacts = ao2_iterator_init(contacts, 0);
-		for (; (contact = ao2_iterator_next(&it_contacts)); ao2_ref(contact, -1)) {
-			ast_str_append(&dial, -1, "PJSIP/");
-
-			if (!ast_strlen_zero(args.request_user)) {
-				ast_str_append(&dial, -1, "%s@", args.request_user);
-			}
-			ast_str_append(&dial, -1, "%s/%s&", args.endpoint_name, contact->uri);
-		}
-		ao2_iterator_destroy(&it_contacts);
-	}
-
-	/* Trim the '&' at the end off */
-	ast_str_truncate(dial, ast_str_strlen(dial) - 1);
-
-	ast_copy_string(buf, ast_str_buffer(dial), len);
-
-	return 0;
-}
-
-static struct ast_custom_function chan_pjsip_dial_contacts_function = {
-	.name = "PJSIP_DIAL_CONTACTS",
-	.read = chan_pjsip_dial_contacts,
-};
-
-static int media_offer_read_av(struct ast_sip_session *session, char *buf,
-			       size_t len, enum ast_format_type media_type)
-{
-	int i, size = 0;
-	struct ast_format fmt;
-	const char *name;
-
-	for (i = 0; ast_codec_pref_index(&session->override_prefs, i, &fmt); ++i) {
-		if (AST_FORMAT_GET_TYPE(fmt.id) != media_type) {
-			continue;
-		}
-
-		name = ast_getformatname(&fmt);
-
-		if (ast_strlen_zero(name)) {
-			ast_log(LOG_WARNING, "PJSIP_MEDIA_OFFER unrecognized format %s\n", name);
-			continue;
-		}
-
-		/* add one since we'll include a comma */
-		size = strlen(name) + 1;
-		len -= size;
-		if ((len) < 0) {
-			break;
-		}
-
-		/* no reason to use strncat here since we have already ensured buf has
-                   enough space, so strcat can be safely used */
-		strcat(buf, name);
-		strcat(buf, ",");
-	}
-
-	if (size) {
-		/* remove the extra comma */
-		buf[strlen(buf) - 1] = '\0';
-	}
-	return 0;
-}
-
-struct media_offer_data {
-	struct ast_sip_session *session;
-	enum ast_format_type media_type;
-	const char *value;
-};
-
-static int media_offer_write_av(void *obj)
-{
-	struct media_offer_data *data = obj;
-	int i;
-	struct ast_format fmt;
-	/* remove all of the given media type first */
-	for (i = 0; ast_codec_pref_index(&data->session->override_prefs, i, &fmt); ++i) {
-		if (AST_FORMAT_GET_TYPE(fmt.id) == data->media_type) {
-			ast_codec_pref_remove(&data->session->override_prefs, &fmt);
-		}
-	}
-	ast_format_cap_remove_bytype(data->session->req_caps, data->media_type);
-	ast_parse_allow_disallow(&data->session->override_prefs, data->session->req_caps, data->value, 1);
-
-	return 0;
-}
-
-static int media_offer_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
-
-	if (!strcmp(data, "audio")) {
-		return media_offer_read_av(channel->session, buf, len, AST_FORMAT_TYPE_AUDIO);
-	} else if (!strcmp(data, "video")) {
-		return media_offer_read_av(channel->session, buf, len, AST_FORMAT_TYPE_VIDEO);
-	}
-
-	return 0;
-}
-
-static int media_offer_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
-{
-	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
-
-	struct media_offer_data mdata = {
-		.session = channel->session,
-		.value = value
-	};
-
-	if (!strcmp(data, "audio")) {
-		mdata.media_type = AST_FORMAT_TYPE_AUDIO;
-	} else if (!strcmp(data, "video")) {
-		mdata.media_type = AST_FORMAT_TYPE_VIDEO;
-	}
-
-	return ast_sip_push_task_synchronous(channel->session->serializer, media_offer_write_av, &mdata);
-}
-
-static struct ast_custom_function media_offer_function = {
-	.name = "PJSIP_MEDIA_OFFER",
-	.read = media_offer_read,
-	.write = media_offer_write
 };
 
 /*! \brief Function called by RTP engine to get local audio RTP peer */
@@ -2080,15 +1855,6 @@
 		goto end;
 	}
 
-	if (ast_custom_function_register(&chan_pjsip_dial_contacts_function)) {
-		ast_log(LOG_ERROR, "Unable to register PJSIP_DIAL_CONTACTS dialplan function\n");
-		goto end;
-	}
-
-	if (ast_custom_function_register(&media_offer_function)) {
-		ast_log(LOG_WARNING, "Unable to register PJSIP_MEDIA_OFFER dialplan function\n");
-	}
-
 	if (ast_sip_session_register_supplement(&chan_pjsip_supplement)) {
 		ast_log(LOG_ERROR, "Unable to register PJSIP supplement\n");
 		goto end;
@@ -2110,8 +1876,6 @@
 	return 0;
 
 end:
-	ast_custom_function_unregister(&media_offer_function);
-	ast_custom_function_unregister(&chan_pjsip_dial_contacts_function);
 	ast_channel_unregister(&chan_pjsip_tech);
 	ast_rtp_glue_unregister(&chan_pjsip_rtp_glue);
 
@@ -2127,13 +1891,10 @@
 /*! \brief Unload the PJSIP channel from Asterisk */
 static int unload_module(void)
 {
-	ast_custom_function_unregister(&media_offer_function);
-
 	ast_sip_session_unregister_supplement(&chan_pjsip_supplement);
 	ast_sip_session_unregister_supplement(&pbx_start_supplement);
 	ast_sip_session_unregister_supplement(&chan_pjsip_ack_supplement);
 
-	ast_custom_function_unregister(&chan_pjsip_dial_contacts_function);
 	ast_channel_unregister(&chan_pjsip_tech);
 	ast_rtp_glue_unregister(&chan_pjsip_rtp_glue);
 

Added: team/mjordan/12-channel-func/channels/pjsip/dialplan_functions.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/12-channel-func/channels/pjsip/dialplan_functions.c?view=auto&rev=403239
==============================================================================
--- team/mjordan/12-channel-func/channels/pjsip/dialplan_functions.c (added)
+++ team/mjordan/12-channel-func/channels/pjsip/dialplan_functions.c Fri Nov 29 22:02:38 2013
@@ -1,0 +1,800 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ *
+ * \author \verbatim Joshua Colp <jcolp at digium.com> \endverbatim
+ * \author \verbatim Matt Jordan <mjordan at digium.com> \endverbatim
+ *
+ * \ingroup functions
+ *
+ * \brief PJSIP channel dialplan functions
+ */
+
+/*** MODULEINFO
+	<support_level>core</support_level>
+ ***/
+
+/*** DOCUMENTATION
+<function name="PJSIP_DIAL_CONTACTS" language="en_US">
+	<synopsis>
+		Return a dial string for dialing all contacts on an AOR.
+	</synopsis>
+	<syntax>
+		<parameter name="endpoint" required="true">
+			<para>Name of the endpoint</para>
+		</parameter>
+		<parameter name="aor" required="false">
+			<para>Name of an AOR to use, if not specified the configured AORs on the endpoint are used</para>
+		</parameter>
+		<parameter name="request_user" required="false">
+			<para>Optional request user to use in the request URI</para>
+		</parameter>
+	</syntax>
+	<description>
+		<para>Returns a properly formatted dial string for dialing all contacts on an AOR.</para>
+	</description>
+</function>
+<function name="PJSIP_MEDIA_OFFER" language="en_US">
+	<synopsis>
+		Media and codec offerings to be set on an outbound SIP channel prior to dialing.
+	</synopsis>
+	<syntax>
+		<parameter name="media" required="true">
+			<para>types of media offered</para>
+		</parameter>
+	</syntax>
+	<description>
+		<para>Returns the codecs offered based upon the media choice</para>
+	</description>
+</function>
+<info name="PJSIPCHANNEL" language="en_US" tech="PJSIP">
+	<enumlist>
+		<enum name="rtp">
+			<para>R/O Retrieve media related information.</para>
+			<para>Specifying <literal>rtp</literal> for <replaceable>item</replaceable>
+			requires two additional parameters, <replaceable>type</replaceable> and
+			<replaceable>media_type</replaceable>.</para>
+			<parameter name="type" required="true">
+				<enumlist>
+					<enum name="src">
+						<para>Retrieve the local address for RTP.</para>
+					</enum>
+					<enum name="dest">
+						<para>Retrieve the remote address for RTP.</para>
+					</enum>
+					<enum name="direct">
+						<para>If direct media is enabled, this address is the remote address
+						used for RTP.</para>
+					</enum>
+					<enum name="secure">
+						<para>Whether or not the media stream is encrypted.</para>
+						<enumlist>
+							<enum name="0">
+								<para>The media stream is not encrypted.</para>
+							</enum>
+							<enum name="1">
+								<para>The media stream is encrypted.</para>
+							</enum>
+						</enumlist>
+					</enum>
+					<enum name="hold">
+						<para>Whether or not the media stream is currently restricted
+						due to a call hold.</para>
+						<enumlist>
+							<enum name="0">
+								<para>The media stream is not held.</para>
+							</enum>
+							<enum name="1">
+								<para>The media stream is held.</para>
+							</enum>
+						</enumlist>
+					</enum>
+				</enumlist>
+			</parameter>
+			<parameter name="media_type" required="false">
+				<enumlist>
+					<enum name="audio">
+						<para>Retrieve information from the audio media stream.</para>
+						<note><para>If not specified, <literal>audio</literal> is used
+						by default.</para></note>
+					</enum>
+					<enum name="video">
+						<para>Retrieve information from the video media stream.</para>
+					</enum>
+				</enumlist>
+			</parameter>
+		</enum>
+		<enum name="rtcp">
+			<para>R/O Retrieve RTCP statistics.</para>
+			<parameter name="statistic" required="true">
+				<enumlist>
+					<enum name="all">
+						<para>Retrieve a summary of all RTCP statistics.</para>
+						<para>The following data items are returned in a semi-colon
+						delineated list:</para>
+						<enumlist>
+							<enum name="ssrc">
+								<para>Our Synchronization Source identifier</para>
+							</enum>
+							<enum name="themssrc">
+								<para>Their Synchronization Source identifier</para>
+							</enum>
+							<enum name="lp">
+								<para>Our lost packet count</para>
+							</enum>
+							<enum name="rxjitter">
+								<para>Received packet jitter</para>
+							</enum>
+							<enum name="rxcount">
+								<para>Received packet count</para>
+							</enum>
+							<enum name="txjitter">
+								<para>Transmitted packet jitter</para>
+							</enum>
+							<enum name="txcount">
+								<para>Transmitted packet count</para>
+							</enum>
+							<enum name="rlp">
+								<para>Remote lost packet count</para>
+							</enum>
+							<enum name="rtt">
+								<para>Round trip time</para>
+							</enum>
+						</enumlist>
+					</enum>
+					<enum name="all_jitter">
+						<para>Retrieve a summary of all RTCP Jitter statistics.</para>
+						<para>The following data items are returned in a semi-colon
+						delineated list:</para>
+						<enumlist>
+							<enum name="minrxjitter">
+								<para>Our minimum jitter</para>
+							</enum>
+							<enum name="maxrxjitter">
+								<para>Our max jitter</para>
+							</enum>
+							<enum name="avgrxjitter">
+								<para>Our average jitter</para>
+							</enum>
+							<enum name="stdevrxjitter">
+								<para>Our jitter standard deviation</para>
+							</enum>
+							<enum name="reported_minjitter">
+								<para>Their minimum jitter</para>
+							</enum>
+							<enum name="reported_maxjitter">
+								<para>Their max jitter</para>
+							</enum>
+							<enum name="reported_avgjitter">
+								<para>Their average jitter</para>
+							</enum>
+							<enum name="reported_stdevjitter">
+								<para>Their jitter standard deviation</para>
+							</enum>
+						</enumlist>
+					</enum>
+					<enum name="all_loss">
+						<para>Retrieve a summary of all RTCP packet loss statistics.</para>
+						<para>The following data items are returned in a semi-colon
+						delineated list:</para>
+						<enumlist>
+							<enum name="minrxlost">
+								<para>Our minimum lost packets</para>
+							</enum>
+							<enum name="maxrxlost">
+								<para>Our max lost packets</para>
+							</enum>
+							<enum name="avgrxlost">
+								<para>Our average lost packets</para>
+							</enum>
+							<enum name="stdevrxlost">
+								<para>Our lost packets standard deviation</para>
+							</enum>
+							<enum name="reported_minlost">
+								<para>Their minimum lost packets</para>
+							</enum>
+							<enum name="reported_maxlost">
+								<para>Their max lost packets</para>
+							</enum>
+							<enum name="reported_avglost">
+								<para>Their average lost packets</para>
+							</enum>
+							<enum name="reported_stdevlost">
+								<para>Their lost packets standard deviation</para>
+							</enum>
+						</enumlist>
+					</enum>
+					<enum name="all_rtt">
+						<para>Retrieve a summary of all RTCP round trip time information.</para>
+						<para>The following data items are returned in a semi-colon
+						delineated list:</para>
+						<enumlist>
+							<enum name="minrtt">
+								<para>Minimum round trip time</para>
+							</enum>
+							<enum name="maxrtt">
+								<para>Maximum round trip time</para>
+							</enum>
+							<enum name="avgrtt">
+								<para>Average round trip time</para>
+							</enum>
+							<enum name="stdevrtt">
+								<para>Standard deviation round trip time</para>
+							</enum>
+						</enumlist>
+					</enum>
+					<enum name="txcount"><para>Transmitted packet count</para></enum>
+					<enum name="rxcount"><para>Received packet count</para></enum>
+					<enum name="txjitter"><para>Transmitted packet jitter</para></enum>
+					<enum name="rxjitter"><para>Received packet jitter</para></enum>
+					<enum name="remote_maxjitter"><para>Their max jitter</para></enum>
+					<enum name="remote_minjitter"><para>Their minimum jitter</para></enum>
+					<enum name="remote_normdevjitter"><para>Their average jitter</para></enum>
+					<enum name="remote_stdevjitter"><para>Their jitter standard deviation</para></enum>
+					<enum name="local_maxjitter"><para>Our max jitter</para></enum>
+					<enum name="local_minjitter"><para>Our minimum jitter</para></enum>
+					<enum name="local_normdevjitter"><para>Our average jitter</para></enum>
+					<enum name="local_stdevjitter"><para>Our jitter standard deviation</para></enum>
+					<enum name="txploss"><para>Transmitted packet loss</para></enum>
+					<enum name="rxploss"><para>Received packet loss</para></enum>
+					<enum name="remote_maxrxploss"><para>Their max lost packets</para></enum>
+					<enum name="remote_minrxploss"><para>Their minimum lost packets</para></enum>
+					<enum name="remote_normdevrxploss"><para>Their average lost packets</para></enum>
+					<enum name="remote_stdevrxploss"><para>Their lost packets standard deviation</para></enum>
+					<enum name="local_maxrxploss"><para>Our max lost packets</para></enum>
+					<enum name="local_minrxploss"><para>Our minimum lost packets</para></enum>
+					<enum name="local_normdevrxploss"><para>Our average lost packets</para></enum>
+					<enum name="local_stdevrxploss"><para>Our lost packets standard deviation</para></enum>
+					<enum name="rtt"><para>Round trip time</para></enum>
+					<enum name="maxrtt"><para>Maximum round trip time</para></enum>
+					<enum name="minrtt"><para>Minimum round trip time</para></enum>
+					<enum name="normdevrtt"><para>Average round trip time</para></enum>
+					<enum name="stdevrtt"><para>Standard deviation round trip time</para></enum>
+					<enum name="local_ssrc"><para>Our Synchronization Source identifier</para></enum>
+					<enum name="remote_ssrc"><para>Their Synchronization Source identifier</para></enum>
+				</enumlist>
+			</parameter>
+			<parameter name="media_type" required="false">
+				<enumlist>
+					<enum name="audio">
+						<para>Retrieve information from the audio media stream.</para>
+						<note><para>If not specified, <literal>audio</literal> is used
+						by default.</para></note>
+					</enum>
+					<enum name="video">
+						<para>Retrieve information from the video media stream.</para>
+					</enum>
+				</enumlist>
+			</parameter>
+		</enum>
+		<enum name="endpoint">
+			<para>The name of the endpoint associated with this channel.
+			Use the <replaceable>PJSIP_ENDPOINT</replaceable> to obtain further
+			endpoint related information.</para>
+		</enum>
+		<enum name="pjsip">
+			<para>Obtain information about the current PJSIP channel and its
+			session.</para>
+			<parameter name="type" required="true">
+			</parameter>
+		</enum>
+	</enumlist>
+</info>
+
+***/
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+#include <pjlib.h>
+#include <pjsip_ua.h>
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/astobj2.h"
+#include "asterisk/module.h"
+#include "asterisk/acl.h"
+#include "asterisk/app.h"
+#include "asterisk/channel.h"
+#include "asterisk/format.h"
+#include "asterisk/pbx.h"
+#include "asterisk/res_pjsip.h"
+#include "asterisk/res_pjsip_session.h"
+#include "include/chan_pjsip.h"
+#include "include/dialplan_functions.h"
+
+static int channel_read_rtp(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
+{
+	struct chan_pjsip_pvt *pvt = ast_channel_tech_pvt(chan);
+	struct ast_sip_session_media *media = NULL;
+	struct ast_sockaddr addr;
+
+	if (!pvt) {
+		ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
+		return -1;
+	}
+
+	if (ast_strlen_zero(type)) {
+		ast_log(AST_LOG_WARNING, "You must supply a type field for 'rtp' information\n");
+		return -1;
+	}
+
+	if (ast_strlen_zero(field) || !strcmp(field, "audio")) {
+		media = pvt->media[SIP_MEDIA_AUDIO];
+	} else if (!strcmp(field, "video")) {
+		media = pvt->media[SIP_MEDIA_VIDEO];
+	} else {
+		ast_log(AST_LOG_WARNING, "Unknown media type field '%s' for 'rtp' information\n", field);
+		return -1;
+	}
+
+	if (!media || !media->rtp) {
+		ast_log(AST_LOG_WARNING, "Channel %s has no media/RTP session\n", ast_channel_name(chan));
+		return -1;
+	}
+
+	if (!strcmp(type, "src")) {
+		ast_rtp_instance_get_local_address(media->rtp, &addr);
+		snprintf(buf, buflen, "%s", ast_sockaddr_stringify(&addr));
+	} else if (!strcmp(type, "dest")) {
+		ast_rtp_instance_get_remote_address(media->rtp, &addr);
+		snprintf(buf, buflen, "%s", ast_sockaddr_stringify(&addr));
+	} else if (!strcmp(type, "direct")) {
+		snprintf(buf, buflen, "%s", ast_sockaddr_stringify(&media->direct_media_addr));
+	} else if (!strcmp(type, "secure")) {
+		snprintf(buf, buflen, "%u", media->srtp ? 1 : 0);
+	} else if (!strcmp(type, "hold")) {
+		snprintf(buf, buflen, "%u", media->held ? 1 : 0);
+	} else {
+		ast_log(AST_LOG_WARNING, "Unknown type field '%s' specified for 'rtp' information\n", type);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int channel_read_rtcp(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
+{
+	struct chan_pjsip_pvt *pvt = ast_channel_tech_pvt(chan);
+	struct ast_sip_session_media *media = NULL;
+
+	if (!pvt) {
+		ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
+		return -1;
+	}
+
+	if (ast_strlen_zero(type)) {
+		ast_log(AST_LOG_WARNING, "You must supply a type field for 'rtcp' information\n");
+		return -1;
+	}
+
+	if (ast_strlen_zero(field) || !strcmp(field, "audio")) {
+		media = pvt->media[SIP_MEDIA_AUDIO];
+	} else if (!strcmp(field, "video")) {
+		media = pvt->media[SIP_MEDIA_VIDEO];
+	} else {
+		ast_log(AST_LOG_WARNING, "Unknown media type field '%s' for 'rtcp' information\n", field);
+		return -1;
+	}
+
+	if (!media || !media->rtp) {
+		ast_log(AST_LOG_WARNING, "Channel %s has no media/RTP session\n", ast_channel_name(chan));
+		return -1;
+	}
+
+	if (!strncasecmp(type, "all", 3)) {
+		enum ast_rtp_instance_stat_field stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY;
+
+		if (!strcasecmp(type, "all_jitter")) {
+			stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER;
+		} else if (!strcasecmp(type, "all_rtt")) {
+			stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT;
+		} else if (!strcasecmp(type, "all_loss")) {
+			stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS;
+		}
+
+		if (!ast_rtp_instance_get_quality(media->rtp, stat_field, buf, buflen)) {
+			ast_log(AST_LOG_WARNING, "Unable to retrieve 'rtcp' statistics for %s\n", ast_channel_name(chan));
+			return -1;
+		}
+	} else {
+		struct ast_rtp_instance_stats stats;
+		int i;
+		struct {
+			const char *name;
+			enum { INT, DBL } type;
+			union {
+				unsigned int *i4;
+				double *d8;
+			};
+		} lookup[] = {
+			{ "txcount",               INT, { .i4 = &stats.txcount, }, },
+			{ "rxcount",               INT, { .i4 = &stats.rxcount, }, },
+			{ "txjitter",              DBL, { .d8 = &stats.txjitter, }, },
+			{ "rxjitter",              DBL, { .d8 = &stats.rxjitter, }, },
+			{ "remote_maxjitter",      DBL, { .d8 = &stats.remote_maxjitter, }, },
+			{ "remote_minjitter",      DBL, { .d8 = &stats.remote_minjitter, }, },
+			{ "remote_normdevjitter",  DBL, { .d8 = &stats.remote_normdevjitter, }, },
+			{ "remote_stdevjitter",    DBL, { .d8 = &stats.remote_stdevjitter, }, },
+			{ "local_maxjitter",       DBL, { .d8 = &stats.local_maxjitter, }, },
+			{ "local_minjitter",       DBL, { .d8 = &stats.local_minjitter, }, },
+			{ "local_normdevjitter",   DBL, { .d8 = &stats.local_normdevjitter, }, },
+			{ "local_stdevjitter",     DBL, { .d8 = &stats.local_stdevjitter, }, },
+			{ "txploss",               INT, { .i4 = &stats.txploss, }, },
+			{ "rxploss",               INT, { .i4 = &stats.rxploss, }, },
+			{ "remote_maxrxploss",     DBL, { .d8 = &stats.remote_maxrxploss, }, },
+			{ "remote_minrxploss",     DBL, { .d8 = &stats.remote_minrxploss, }, },
+			{ "remote_normdevrxploss", DBL, { .d8 = &stats.remote_normdevrxploss, }, },
+			{ "remote_stdevrxploss",   DBL, { .d8 = &stats.remote_stdevrxploss, }, },
+			{ "local_maxrxploss",      DBL, { .d8 = &stats.local_maxrxploss, }, },
+			{ "local_minrxploss",      DBL, { .d8 = &stats.local_minrxploss, }, },
+			{ "local_normdevrxploss",  DBL, { .d8 = &stats.local_normdevrxploss, }, },
+			{ "local_stdevrxploss",    DBL, { .d8 = &stats.local_stdevrxploss, }, },
+			{ "rtt",                   DBL, { .d8 = &stats.rtt, }, },
+			{ "maxrtt",                DBL, { .d8 = &stats.maxrtt, }, },
+			{ "minrtt",                DBL, { .d8 = &stats.minrtt, }, },
+			{ "normdevrtt",            DBL, { .d8 = &stats.normdevrtt, }, },
+			{ "stdevrtt",              DBL, { .d8 = &stats.stdevrtt, }, },
+			{ "local_ssrc",            INT, { .i4 = &stats.local_ssrc, }, },
+			{ "remote_ssrc",           INT, { .i4 = &stats.remote_ssrc, }, },
+			{ NULL, },
+		};
+
+		if (ast_rtp_instance_get_stats(media->rtp, &stats, AST_RTP_INSTANCE_STAT_ALL)) {
+			ast_log(AST_LOG_WARNING, "Unable to retrieve 'rtcp' statistics for %s\n", ast_channel_name(chan));
+			return -1;
+		}
+
+		for (i = 0; !ast_strlen_zero(lookup[i].name); i++) {
+			if (!strcasecmp(type, lookup[i].name)) {
+				if (lookup[i].type == INT) {
+					snprintf(buf, buflen, "%u", *lookup[i].i4);
+				} else {
+					snprintf(buf, buflen, "%f", *lookup[i].d8);
+				}
+				return 0;
+			}
+		}
+		ast_log(AST_LOG_WARNING, "Unrecognized argument '%s' for 'rtcp' information\n", type);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int channel_read_pjsip(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
+{
+	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
+	pjsip_dialog *dlg;
+
+	if (!channel) {
+		ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
+		return -1;
+	}
+
+	dlg = channel->session->inv_session->dlg;
+
+	if (!strcmp(type, "secure")) {
+		snprintf(buf, buflen, "%u", dlg->secure ? 1 : 0);
+	} else if (!strcmp(type, "target_uri")) {
+		dlg->target->vptr->p_print(PJSIP_URI_IN_REQ_URI, dlg->target, buf, buflen);
+	} else if (!strcmp(type, "local_uri")) {
+		dlg->local.info->uri->vptr->p_print(PJSIP_URI_IN_FROMTO_HDR,
+			dlg->local.info->uri, buf, buflen);
+	} else if (!strcmp(type, "remote_uri")) {
+		dlg->remote.info->uri->vptr->p_print(PJSIP_URI_IN_FROMTO_HDR,
+			dlg->remote.info->uri, buf, buflen);
+	} else {
+		return -1;
+	}
+
+	// pjsip_uri ->target
+	// pjsip_dlg_party ->local
+	//		pjsip_fromto_hdr ->info
+	//			pjsip_uri 		->uri
+	//				uri->p_print(
+	//				PJSIP_URI_IN_FROMTO_HDR, uri, buf, size);
+	// pjsip_dlg_party ->remote
+	// pj_bool_t ->secure
+
+	return 0;
+}
+	// secure_signalling
+	//  get from pjsip_dlg secure
+	// t38passthrough
+	// 
+
+	// things to get from pjsip_dialog instance:
+	//  pjsip_user_agent *ua
+	//  pjsip_uri *target (URI of who we are talking to)
+	//  pjsip_dlg_party local
+	//      pjsip_fromto_hdr *info
+	//          pjsip_uri *uri
+	//      pjsip_contact_hdr *contact
+	//          pjsip_uri *uri
+	//  pjsip_dlg_party remote
+
+	// transport information will be harder. When we rx data, we'll need to
+	// store it on the channel in a datastore. Can't really get this info from
+	// the dialog...?
+	//  type
+	//  pjsip_host_port local_name
+	//  pjsip_host_port remote_name
+
+/*! \brief Callback function for CHANNEL function read */
+int pjsip_acf_channel_read(struct ast_channel *chan, const char *funcname, char *preparse, char *buf, size_t buflen)
+{
+
+	char *parse = ast_strdupa(preparse);
+	int res = 0;
+
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(param);
+		AST_APP_ARG(type);
+		AST_APP_ARG(field);
+	);
+		
+	/* Check for zero arguments */
+	if (ast_strlen_zero(parse)) {
+		ast_log(LOG_ERROR, "Cannot call %s without arguments\n", funcname);
+		return -1;
+	}
+
+	AST_STANDARD_APP_ARGS(args, parse);
+
+	/* Sanity check */
+	if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
+		ast_log(LOG_ERROR, "Cannot call %s on a non-PJSIP channel\n", funcname);
+		return 0;
+	}
+
+	memset(buf, 0, buflen);
+
+	if (!strcmp(args.param, "rtp")) {
+		res = channel_read_rtp(chan, args.type, args.field, buf, buflen);
+	} else if (!strcmp(args.param, "rtcp")) {
+		res = channel_read_rtcp(chan, args.type, args.field, buf, buflen);
+	} else if (!strcmp(args.param, "endpoint")) {
+		struct ast_sip_channel_pvt *pvt = ast_channel_tech_pvt(chan);
+
+		if (!pvt) {
+			ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
+			return -1;
+		}
+		if (!pvt->session || !pvt->session->endpoint) {
+			ast_log(AST_LOG_WARNING, "Channel %s has no endpoint!\n", ast_channel_name(chan));
+			return -1;
+		}
+		snprintf(buf, buflen, "%s", ast_sorcery_object_get_id(pvt->session->endpoint));
+	} else if (!strcmp(args.param, "pjsip")) {
+		res = channel_read_pjsip(chan, args.type, args.field, buf, buflen);
+	} else {
+		res = -1;
+	}
+
+	return res;
+}
+
+/*! \brief Dialplan function for constructing a dial string for calling all contacts */
+static int chan_pjsip_dial_contacts(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_str *, dial, NULL, ast_free_ptr);
+	const char *aor_name;
+	char *rest;
+
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(endpoint_name);
+		AST_APP_ARG(aor_name);
+		AST_APP_ARG(request_user);
+	);
+
+	AST_STANDARD_APP_ARGS(args, data);
+
+	if (ast_strlen_zero(args.endpoint_name)) {
+		ast_log(LOG_WARNING, "An endpoint name must be specified when using the '%s' dialplan function\n", cmd);
+		return -1;
+	} else if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", args.endpoint_name))) {
+		ast_log(LOG_WARNING, "Specified endpoint '%s' was not found\n", args.endpoint_name);
+		return -1;
+	}
+
+	aor_name = S_OR(args.aor_name, endpoint->aors);
+
+	if (ast_strlen_zero(aor_name)) {
+		ast_log(LOG_WARNING, "No AOR has been provided and no AORs are configured on endpoint '%s'\n", args.endpoint_name);
+		return -1;
+	} else if (!(dial = ast_str_create(len))) {
+		ast_log(LOG_WARNING, "Could not get enough buffer space for dialing contacts\n");
+		return -1;
+	} else if (!(rest = ast_strdupa(aor_name))) {
+		ast_log(LOG_WARNING, "Could not duplicate provided AORs\n");
+		return -1;
+	}
+
+	while ((aor_name = strsep(&rest, ","))) {
+		RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup);
+		RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
+		struct ao2_iterator it_contacts;
+		struct ast_sip_contact *contact;
+
+		if (!aor) {
+			/* If the AOR provided is not found skip it, there may be more */
+			continue;
+		} else if (!(contacts = ast_sip_location_retrieve_aor_contacts(aor))) {
+			/* No contacts are available, skip it as well */
+			continue;
+		} else if (!ao2_container_count(contacts)) {
+			/* We were given a container but no contacts are in it... */
+			continue;
+		}
+
+		it_contacts = ao2_iterator_init(contacts, 0);
+		for (; (contact = ao2_iterator_next(&it_contacts)); ao2_ref(contact, -1)) {
+			ast_str_append(&dial, -1, "PJSIP/");
+
+			if (!ast_strlen_zero(args.request_user)) {
+				ast_str_append(&dial, -1, "%s@", args.request_user);
+			}
+			ast_str_append(&dial, -1, "%s/%s&", args.endpoint_name, contact->uri);
+		}
+		ao2_iterator_destroy(&it_contacts);
+	}
+
+	/* Trim the '&' at the end off */
+	ast_str_truncate(dial, ast_str_strlen(dial) - 1);
+
+	ast_copy_string(buf, ast_str_buffer(dial), len);
+
+	return 0;
+}
+
+static struct ast_custom_function chan_pjsip_dial_contacts_function = {
+	.name = "PJSIP_DIAL_CONTACTS",
+	.read = chan_pjsip_dial_contacts,
+};
+
+static int media_offer_read_av(struct ast_sip_session *session, char *buf,
+			       size_t len, enum ast_format_type media_type)
+{
+	int i, size = 0;
+	struct ast_format fmt;
+	const char *name;
+
+	for (i = 0; ast_codec_pref_index(&session->override_prefs, i, &fmt); ++i) {
+		if (AST_FORMAT_GET_TYPE(fmt.id) != media_type) {
+			continue;
+		}
+
+		name = ast_getformatname(&fmt);
+
+		if (ast_strlen_zero(name)) {
+			ast_log(LOG_WARNING, "PJSIP_MEDIA_OFFER unrecognized format %s\n", name);
+			continue;
+		}
+
+		/* add one since we'll include a comma */
+		size = strlen(name) + 1;
+		len -= size;
+		if ((len) < 0) {
+			break;
+		}
+
+		/* no reason to use strncat here since we have already ensured buf has
+                   enough space, so strcat can be safely used */
+		strcat(buf, name);
+		strcat(buf, ",");
+	}
+
+	if (size) {
+		/* remove the extra comma */
+		buf[strlen(buf) - 1] = '\0';
+	}
+	return 0;
+}
+
+struct media_offer_data {
+	struct ast_sip_session *session;
+	enum ast_format_type media_type;
+	const char *value;
+};
+
+static int media_offer_write_av(void *obj)
+{
+	struct media_offer_data *data = obj;
+	int i;
+	struct ast_format fmt;
+	/* remove all of the given media type first */

[... 739 lines stripped ...]



More information about the svn-commits mailing list