pjsip/dialplan_functions.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2013, Digium, Inc.
00005  *
00006  * See http://www.asterisk.org for more information about
00007  * the Asterisk project. Please do not directly contact
00008  * any of the maintainers of this project for assistance;
00009  * the project provides a web site, mailing lists and IRC
00010  * channels for your use.
00011  *
00012  * This program is free software, distributed under the terms of
00013  * the GNU General Public License Version 2. See the LICENSE file
00014  * at the top of the source tree.
00015  */
00016 
00017 /*!
00018  * \file
00019  *
00020  * \author \verbatim Joshua Colp <jcolp@digium.com> \endverbatim
00021  * \author \verbatim Matt Jordan <mjordan@digium.com> \endverbatim
00022  *
00023  * \ingroup functions
00024  *
00025  * \brief PJSIP channel dialplan functions
00026  */
00027 
00028 /*** MODULEINFO
00029    <support_level>core</support_level>
00030  ***/
00031 
00032 /*** DOCUMENTATION
00033 <function name="PJSIP_DIAL_CONTACTS" language="en_US">
00034    <synopsis>
00035       Return a dial string for dialing all contacts on an AOR.
00036    </synopsis>
00037    <syntax>
00038       <parameter name="endpoint" required="true">
00039          <para>Name of the endpoint</para>
00040       </parameter>
00041       <parameter name="aor" required="false">
00042          <para>Name of an AOR to use, if not specified the configured AORs on the endpoint are used</para>
00043       </parameter>
00044       <parameter name="request_user" required="false">
00045          <para>Optional request user to use in the request URI</para>
00046       </parameter>
00047    </syntax>
00048    <description>
00049       <para>Returns a properly formatted dial string for dialing all contacts on an AOR.</para>
00050    </description>
00051 </function>
00052 <function name="PJSIP_MEDIA_OFFER" language="en_US">
00053    <synopsis>
00054       Media and codec offerings to be set on an outbound SIP channel prior to dialing.
00055    </synopsis>
00056    <syntax>
00057       <parameter name="media" required="true">
00058          <para>types of media offered</para>
00059       </parameter>
00060    </syntax>
00061    <description>
00062       <para>Returns the codecs offered based upon the media choice</para>
00063    </description>
00064 </function>
00065 <info name="PJSIPCHANNEL" language="en_US" tech="PJSIP">
00066    <enumlist>
00067       <enum name="rtp">
00068          <para>R/O Retrieve media related information.</para>
00069          <parameter name="type" required="true">
00070             <para>When <replaceable>rtp</replaceable> is specified, the
00071             <literal>type</literal> parameter must be provided. It specifies
00072             which RTP parameter to read.</para>
00073             <enumlist>
00074                <enum name="src">
00075                   <para>Retrieve the local address for RTP.</para>
00076                </enum>
00077                <enum name="dest">
00078                   <para>Retrieve the remote address for RTP.</para>
00079                </enum>
00080                <enum name="direct">
00081                   <para>If direct media is enabled, this address is the remote address
00082                   used for RTP.</para>
00083                </enum>
00084                <enum name="secure">
00085                   <para>Whether or not the media stream is encrypted.</para>
00086                   <enumlist>
00087                      <enum name="0">
00088                         <para>The media stream is not encrypted.</para>
00089                      </enum>
00090                      <enum name="1">
00091                         <para>The media stream is encrypted.</para>
00092                      </enum>
00093                   </enumlist>
00094                </enum>
00095                <enum name="hold">
00096                   <para>Whether or not the media stream is currently restricted
00097                   due to a call hold.</para>
00098                   <enumlist>
00099                      <enum name="0">
00100                         <para>The media stream is not held.</para>
00101                      </enum>
00102                      <enum name="1">
00103                         <para>The media stream is held.</para>
00104                      </enum>
00105                   </enumlist>
00106                </enum>
00107             </enumlist>
00108          </parameter>
00109          <parameter name="media_type" required="false">
00110             <para>When <replaceable>rtp</replaceable> is specified, the
00111             <literal>media_type</literal> parameter may be provided. It specifies
00112             which media stream the chosen RTP parameter should be retrieved
00113             from.</para>
00114             <enumlist>
00115                <enum name="audio">
00116                   <para>Retrieve information from the audio media stream.</para>
00117                   <note><para>If not specified, <literal>audio</literal> is used
00118                   by default.</para></note>
00119                </enum>
00120                <enum name="video">
00121                   <para>Retrieve information from the video media stream.</para>
00122                </enum>
00123             </enumlist>
00124          </parameter>
00125       </enum>
00126       <enum name="rtcp">
00127          <para>R/O Retrieve RTCP statistics.</para>
00128          <parameter name="statistic" required="true">
00129             <para>When <replaceable>rtcp</replaceable> is specified, the
00130             <literal>statistic</literal> parameter must be provided. It specifies
00131             which RTCP statistic parameter to read.</para>
00132             <enumlist>
00133                <enum name="all">
00134                   <para>Retrieve a summary of all RTCP statistics.</para>
00135                   <para>The following data items are returned in a semi-colon
00136                   delineated list:</para>
00137                   <enumlist>
00138                      <enum name="ssrc">
00139                         <para>Our Synchronization Source identifier</para>
00140                      </enum>
00141                      <enum name="themssrc">
00142                         <para>Their Synchronization Source identifier</para>
00143                      </enum>
00144                      <enum name="lp">
00145                         <para>Our lost packet count</para>
00146                      </enum>
00147                      <enum name="rxjitter">
00148                         <para>Received packet jitter</para>
00149                      </enum>
00150                      <enum name="rxcount">
00151                         <para>Received packet count</para>
00152                      </enum>
00153                      <enum name="txjitter">
00154                         <para>Transmitted packet jitter</para>
00155                      </enum>
00156                      <enum name="txcount">
00157                         <para>Transmitted packet count</para>
00158                      </enum>
00159                      <enum name="rlp">
00160                         <para>Remote lost packet count</para>
00161                      </enum>
00162                      <enum name="rtt">
00163                         <para>Round trip time</para>
00164                      </enum>
00165                   </enumlist>
00166                </enum>
00167                <enum name="all_jitter">
00168                   <para>Retrieve a summary of all RTCP Jitter statistics.</para>
00169                   <para>The following data items are returned in a semi-colon
00170                   delineated list:</para>
00171                   <enumlist>
00172                      <enum name="minrxjitter">
00173                         <para>Our minimum jitter</para>
00174                      </enum>
00175                      <enum name="maxrxjitter">
00176                         <para>Our max jitter</para>
00177                      </enum>
00178                      <enum name="avgrxjitter">
00179                         <para>Our average jitter</para>
00180                      </enum>
00181                      <enum name="stdevrxjitter">
00182                         <para>Our jitter standard deviation</para>
00183                      </enum>
00184                      <enum name="reported_minjitter">
00185                         <para>Their minimum jitter</para>
00186                      </enum>
00187                      <enum name="reported_maxjitter">
00188                         <para>Their max jitter</para>
00189                      </enum>
00190                      <enum name="reported_avgjitter">
00191                         <para>Their average jitter</para>
00192                      </enum>
00193                      <enum name="reported_stdevjitter">
00194                         <para>Their jitter standard deviation</para>
00195                      </enum>
00196                   </enumlist>
00197                </enum>
00198                <enum name="all_loss">
00199                   <para>Retrieve a summary of all RTCP packet loss statistics.</para>
00200                   <para>The following data items are returned in a semi-colon
00201                   delineated list:</para>
00202                   <enumlist>
00203                      <enum name="minrxlost">
00204                         <para>Our minimum lost packets</para>
00205                      </enum>
00206                      <enum name="maxrxlost">
00207                         <para>Our max lost packets</para>
00208                      </enum>
00209                      <enum name="avgrxlost">
00210                         <para>Our average lost packets</para>
00211                      </enum>
00212                      <enum name="stdevrxlost">
00213                         <para>Our lost packets standard deviation</para>
00214                      </enum>
00215                      <enum name="reported_minlost">
00216                         <para>Their minimum lost packets</para>
00217                      </enum>
00218                      <enum name="reported_maxlost">
00219                         <para>Their max lost packets</para>
00220                      </enum>
00221                      <enum name="reported_avglost">
00222                         <para>Their average lost packets</para>
00223                      </enum>
00224                      <enum name="reported_stdevlost">
00225                         <para>Their lost packets standard deviation</para>
00226                      </enum>
00227                   </enumlist>
00228                </enum>
00229                <enum name="all_rtt">
00230                   <para>Retrieve a summary of all RTCP round trip time information.</para>
00231                   <para>The following data items are returned in a semi-colon
00232                   delineated list:</para>
00233                   <enumlist>
00234                      <enum name="minrtt">
00235                         <para>Minimum round trip time</para>
00236                      </enum>
00237                      <enum name="maxrtt">
00238                         <para>Maximum round trip time</para>
00239                      </enum>
00240                      <enum name="avgrtt">
00241                         <para>Average round trip time</para>
00242                      </enum>
00243                      <enum name="stdevrtt">
00244                         <para>Standard deviation round trip time</para>
00245                      </enum>
00246                   </enumlist>
00247                </enum>
00248                <enum name="txcount"><para>Transmitted packet count</para></enum>
00249                <enum name="rxcount"><para>Received packet count</para></enum>
00250                <enum name="txjitter"><para>Transmitted packet jitter</para></enum>
00251                <enum name="rxjitter"><para>Received packet jitter</para></enum>
00252                <enum name="remote_maxjitter"><para>Their max jitter</para></enum>
00253                <enum name="remote_minjitter"><para>Their minimum jitter</para></enum>
00254                <enum name="remote_normdevjitter"><para>Their average jitter</para></enum>
00255                <enum name="remote_stdevjitter"><para>Their jitter standard deviation</para></enum>
00256                <enum name="local_maxjitter"><para>Our max jitter</para></enum>
00257                <enum name="local_minjitter"><para>Our minimum jitter</para></enum>
00258                <enum name="local_normdevjitter"><para>Our average jitter</para></enum>
00259                <enum name="local_stdevjitter"><para>Our jitter standard deviation</para></enum>
00260                <enum name="txploss"><para>Transmitted packet loss</para></enum>
00261                <enum name="rxploss"><para>Received packet loss</para></enum>
00262                <enum name="remote_maxrxploss"><para>Their max lost packets</para></enum>
00263                <enum name="remote_minrxploss"><para>Their minimum lost packets</para></enum>
00264                <enum name="remote_normdevrxploss"><para>Their average lost packets</para></enum>
00265                <enum name="remote_stdevrxploss"><para>Their lost packets standard deviation</para></enum>
00266                <enum name="local_maxrxploss"><para>Our max lost packets</para></enum>
00267                <enum name="local_minrxploss"><para>Our minimum lost packets</para></enum>
00268                <enum name="local_normdevrxploss"><para>Our average lost packets</para></enum>
00269                <enum name="local_stdevrxploss"><para>Our lost packets standard deviation</para></enum>
00270                <enum name="rtt"><para>Round trip time</para></enum>
00271                <enum name="maxrtt"><para>Maximum round trip time</para></enum>
00272                <enum name="minrtt"><para>Minimum round trip time</para></enum>
00273                <enum name="normdevrtt"><para>Average round trip time</para></enum>
00274                <enum name="stdevrtt"><para>Standard deviation round trip time</para></enum>
00275                <enum name="local_ssrc"><para>Our Synchronization Source identifier</para></enum>
00276                <enum name="remote_ssrc"><para>Their Synchronization Source identifier</para></enum>
00277             </enumlist>
00278          </parameter>
00279          <parameter name="media_type" required="false">
00280             <para>When <replaceable>rtcp</replaceable> is specified, the
00281             <literal>media_type</literal> parameter may be provided. It specifies
00282             which media stream the chosen RTCP parameter should be retrieved
00283             from.</para>
00284             <enumlist>
00285                <enum name="audio">
00286                   <para>Retrieve information from the audio media stream.</para>
00287                   <note><para>If not specified, <literal>audio</literal> is used
00288                   by default.</para></note>
00289                </enum>
00290                <enum name="video">
00291                   <para>Retrieve information from the video media stream.</para>
00292                </enum>
00293             </enumlist>
00294          </parameter>
00295       </enum>
00296       <enum name="endpoint">
00297          <para>R/O The name of the endpoint associated with this channel.
00298          Use the <replaceable>PJSIP_ENDPOINT</replaceable> function to obtain
00299          further endpoint related information.</para>
00300       </enum>
00301       <enum name="contact">
00302          <para>R/O The name of the contact associated with this channel.
00303          Use the <replaceable>PJSIP_CONTACT</replaceable> function to obtain
00304          further contact related information. Note this may not be present and if so
00305          is only available on outgoing legs.</para>
00306       </enum>
00307       <enum name="aor">
00308          <para>R/O The name of the AOR associated with this channel.
00309          Use the <replaceable>PJSIP_AOR</replaceable> function to obtain
00310          further AOR related information. Note this may not be present and if so
00311          is only available on outgoing legs.</para>
00312       </enum>
00313       <enum name="pjsip">
00314          <para>R/O Obtain information about the current PJSIP channel and its
00315          session.</para>
00316          <parameter name="type" required="true">
00317             <para>When <replaceable>pjsip</replaceable> is specified, the
00318             <literal>type</literal> parameter must be provided. It specifies
00319             which signalling parameter to read.</para>
00320             <enumlist>
00321                <enum name="secure">
00322                   <para>Whether or not the signalling uses a secure transport.</para>
00323                   <enumlist>
00324                      <enum name="0"><para>The signalling uses a non-secure transport.</para></enum>
00325                      <enum name="1"><para>The signalling uses a secure transport.</para></enum>
00326                   </enumlist>
00327                </enum>
00328                <enum name="target_uri">
00329                   <para>The request URI of the <literal>INVITE</literal> request associated with the creation of this channel.</para>
00330                </enum>
00331                <enum name="local_uri">
00332                   <para>The local URI.</para>
00333                </enum>
00334                <enum name="remote_uri">
00335                   <para>The remote URI.</para>
00336                </enum>
00337                <enum name="t38state">
00338                   <para>The current state of any T.38 fax on this channel.</para>
00339                   <enumlist>
00340                      <enum name="DISABLED"><para>T.38 faxing is disabled on this channel.</para></enum>
00341                      <enum name="LOCAL_REINVITE"><para>Asterisk has sent a <literal>re-INVITE</literal> to the remote end to initiate a T.38 fax.</para></enum>
00342                      <enum name="REMOTE_REINVITE"><para>The remote end has sent a <literal>re-INVITE</literal> to Asterisk to initiate a T.38 fax.</para></enum>
00343                      <enum name="ENABLED"><para>A T.38 fax session has been enabled.</para></enum>
00344                      <enum name="REJECTED"><para>A T.38 fax session was attempted but was rejected.</para></enum>
00345                   </enumlist>
00346                </enum>
00347                <enum name="local_addr">
00348                   <para>On inbound calls, the full IP address and port number that
00349                   the <literal>INVITE</literal> request was received on. On outbound
00350                   calls, the full IP address and port number that the <literal>INVITE</literal>
00351                   request was transmitted from.</para>
00352                </enum>
00353                <enum name="remote_addr">
00354                   <para>On inbound calls, the full IP address and port number that
00355                   the <literal>INVITE</literal> request was received from. On outbound
00356                   calls, the full IP address and port number that the <literal>INVITE</literal>
00357                   request was transmitted to.</para>
00358                </enum>
00359             </enumlist>
00360          </parameter>
00361       </enum>
00362    </enumlist>
00363 </info>
00364 ***/
00365 
00366 #include "asterisk.h"
00367 
00368 #include <pjsip.h>
00369 #include <pjlib.h>
00370 #include <pjsip_ua.h>
00371 
00372 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 434471 $")
00373 
00374 #include "asterisk/astobj2.h"
00375 #include "asterisk/module.h"
00376 #include "asterisk/acl.h"
00377 #include "asterisk/app.h"
00378 #include "asterisk/channel.h"
00379 #include "asterisk/format.h"
00380 #include "asterisk/pbx.h"
00381 #include "asterisk/res_pjsip.h"
00382 #include "asterisk/res_pjsip_session.h"
00383 #include "include/chan_pjsip.h"
00384 #include "include/dialplan_functions.h"
00385 
00386 /*!
00387  * \brief String representations of the T.38 state enum
00388  */
00389 static const char *t38state_to_string[T38_MAX_ENUM] = {
00390    [T38_DISABLED] = "DISABLED",
00391    [T38_LOCAL_REINVITE] = "LOCAL_REINVITE",
00392    [T38_PEER_REINVITE] = "REMOTE_REINVITE",
00393    [T38_ENABLED] = "ENABLED",
00394    [T38_REJECTED] = "REJECTED",
00395 };
00396 
00397 /*!
00398  * \internal \brief Handle reading RTP information
00399  */
00400 static int channel_read_rtp(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
00401 {
00402    struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
00403    struct chan_pjsip_pvt *pvt;
00404    struct ast_sip_session_media *media = NULL;
00405    struct ast_sockaddr addr;
00406 
00407    if (!channel) {
00408       ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
00409       return -1;
00410    }
00411 
00412    pvt = channel->pvt;
00413    if (!pvt) {
00414       ast_log(AST_LOG_WARNING, "Channel %s has no chan_pjsip pvt!\n", ast_channel_name(chan));
00415       return -1;
00416    }
00417 
00418    if (ast_strlen_zero(type)) {
00419       ast_log(AST_LOG_WARNING, "You must supply a type field for 'rtp' information\n");
00420       return -1;
00421    }
00422 
00423    if (ast_strlen_zero(field) || !strcmp(field, "audio")) {
00424       media = pvt->media[SIP_MEDIA_AUDIO];
00425    } else if (!strcmp(field, "video")) {
00426       media = pvt->media[SIP_MEDIA_VIDEO];
00427    } else {
00428       ast_log(AST_LOG_WARNING, "Unknown media type field '%s' for 'rtp' information\n", field);
00429       return -1;
00430    }
00431 
00432    if (!media || !media->rtp) {
00433       ast_log(AST_LOG_WARNING, "Channel %s has no %s media/RTP session\n",
00434          ast_channel_name(chan), S_OR(field, "audio"));
00435       return -1;
00436    }
00437 
00438    if (!strcmp(type, "src")) {
00439       ast_rtp_instance_get_local_address(media->rtp, &addr);
00440       ast_copy_string(buf, ast_sockaddr_stringify(&addr), buflen);
00441    } else if (!strcmp(type, "dest")) {
00442       ast_rtp_instance_get_remote_address(media->rtp, &addr);
00443       ast_copy_string(buf, ast_sockaddr_stringify(&addr), buflen);
00444    } else if (!strcmp(type, "direct")) {
00445       ast_copy_string(buf, ast_sockaddr_stringify(&media->direct_media_addr), buflen);
00446    } else if (!strcmp(type, "secure")) {
00447       snprintf(buf, buflen, "%d", media->srtp ? 1 : 0);
00448    } else if (!strcmp(type, "hold")) {
00449       snprintf(buf, buflen, "%d", media->remotely_held ? 1 : 0);
00450    } else {
00451       ast_log(AST_LOG_WARNING, "Unknown type field '%s' specified for 'rtp' information\n", type);
00452       return -1;
00453    }
00454 
00455    return 0;
00456 }
00457 
00458 /*!
00459  * \internal \brief Handle reading RTCP information
00460  */
00461 static int channel_read_rtcp(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
00462 {
00463    struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
00464    struct chan_pjsip_pvt *pvt;
00465    struct ast_sip_session_media *media = NULL;
00466 
00467    if (!channel) {
00468       ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
00469       return -1;
00470    }
00471 
00472    pvt = channel->pvt;
00473    if (!pvt) {
00474       ast_log(AST_LOG_WARNING, "Channel %s has no chan_pjsip pvt!\n", ast_channel_name(chan));
00475       return -1;
00476    }
00477 
00478    if (ast_strlen_zero(type)) {
00479       ast_log(AST_LOG_WARNING, "You must supply a type field for 'rtcp' information\n");
00480       return -1;
00481    }
00482 
00483    if (ast_strlen_zero(field) || !strcmp(field, "audio")) {
00484       media = pvt->media[SIP_MEDIA_AUDIO];
00485    } else if (!strcmp(field, "video")) {
00486       media = pvt->media[SIP_MEDIA_VIDEO];
00487    } else {
00488       ast_log(AST_LOG_WARNING, "Unknown media type field '%s' for 'rtcp' information\n", field);
00489       return -1;
00490    }
00491 
00492    if (!media || !media->rtp) {
00493       ast_log(AST_LOG_WARNING, "Channel %s has no %s media/RTP session\n",
00494          ast_channel_name(chan), S_OR(field, "audio"));
00495       return -1;
00496    }
00497 
00498    if (!strncasecmp(type, "all", 3)) {
00499       enum ast_rtp_instance_stat_field stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY;
00500 
00501       if (!strcasecmp(type, "all_jitter")) {
00502          stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER;
00503       } else if (!strcasecmp(type, "all_rtt")) {
00504          stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT;
00505       } else if (!strcasecmp(type, "all_loss")) {
00506          stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS;
00507       }
00508 
00509       if (!ast_rtp_instance_get_quality(media->rtp, stat_field, buf, buflen)) {
00510          ast_log(AST_LOG_WARNING, "Unable to retrieve 'rtcp' statistics for %s\n", ast_channel_name(chan));
00511          return -1;
00512       }
00513    } else {
00514       struct ast_rtp_instance_stats stats;
00515       int i;
00516       struct {
00517          const char *name;
00518          enum { INT, DBL } type;
00519          union {
00520             unsigned int *i4;
00521             double *d8;
00522          };
00523       } lookup[] = {
00524          { "txcount",               INT, { .i4 = &stats.txcount, }, },
00525          { "rxcount",               INT, { .i4 = &stats.rxcount, }, },
00526          { "txjitter",              DBL, { .d8 = &stats.txjitter, }, },
00527          { "rxjitter",              DBL, { .d8 = &stats.rxjitter, }, },
00528          { "remote_maxjitter",      DBL, { .d8 = &stats.remote_maxjitter, }, },
00529          { "remote_minjitter",      DBL, { .d8 = &stats.remote_minjitter, }, },
00530          { "remote_normdevjitter",  DBL, { .d8 = &stats.remote_normdevjitter, }, },
00531          { "remote_stdevjitter",    DBL, { .d8 = &stats.remote_stdevjitter, }, },
00532          { "local_maxjitter",       DBL, { .d8 = &stats.local_maxjitter, }, },
00533          { "local_minjitter",       DBL, { .d8 = &stats.local_minjitter, }, },
00534          { "local_normdevjitter",   DBL, { .d8 = &stats.local_normdevjitter, }, },
00535          { "local_stdevjitter",     DBL, { .d8 = &stats.local_stdevjitter, }, },
00536          { "txploss",               INT, { .i4 = &stats.txploss, }, },
00537          { "rxploss",               INT, { .i4 = &stats.rxploss, }, },
00538          { "remote_maxrxploss",     DBL, { .d8 = &stats.remote_maxrxploss, }, },
00539          { "remote_minrxploss",     DBL, { .d8 = &stats.remote_minrxploss, }, },
00540          { "remote_normdevrxploss", DBL, { .d8 = &stats.remote_normdevrxploss, }, },
00541          { "remote_stdevrxploss",   DBL, { .d8 = &stats.remote_stdevrxploss, }, },
00542          { "local_maxrxploss",      DBL, { .d8 = &stats.local_maxrxploss, }, },
00543          { "local_minrxploss",      DBL, { .d8 = &stats.local_minrxploss, }, },
00544          { "local_normdevrxploss",  DBL, { .d8 = &stats.local_normdevrxploss, }, },
00545          { "local_stdevrxploss",    DBL, { .d8 = &stats.local_stdevrxploss, }, },
00546          { "rtt",                   DBL, { .d8 = &stats.rtt, }, },
00547          { "maxrtt",                DBL, { .d8 = &stats.maxrtt, }, },
00548          { "minrtt",                DBL, { .d8 = &stats.minrtt, }, },
00549          { "normdevrtt",            DBL, { .d8 = &stats.normdevrtt, }, },
00550          { "stdevrtt",              DBL, { .d8 = &stats.stdevrtt, }, },
00551          { "local_ssrc",            INT, { .i4 = &stats.local_ssrc, }, },
00552          { "remote_ssrc",           INT, { .i4 = &stats.remote_ssrc, }, },
00553          { NULL, },
00554       };
00555 
00556       if (ast_rtp_instance_get_stats(media->rtp, &stats, AST_RTP_INSTANCE_STAT_ALL)) {
00557          ast_log(AST_LOG_WARNING, "Unable to retrieve 'rtcp' statistics for %s\n", ast_channel_name(chan));
00558          return -1;
00559       }
00560 
00561       for (i = 0; !ast_strlen_zero(lookup[i].name); i++) {
00562          if (!strcasecmp(type, lookup[i].name)) {
00563             if (lookup[i].type == INT) {
00564                snprintf(buf, buflen, "%u", *lookup[i].i4);
00565             } else {
00566                snprintf(buf, buflen, "%f", *lookup[i].d8);
00567             }
00568             return 0;
00569          }
00570       }
00571       ast_log(AST_LOG_WARNING, "Unrecognized argument '%s' for 'rtcp' information\n", type);
00572       return -1;
00573    }
00574 
00575    return 0;
00576 }
00577 
00578 /*!
00579  * \internal \brief Handle reading signalling information
00580  */
00581 static int channel_read_pjsip(struct ast_channel *chan, const char *type, const char *field, char *buf, size_t buflen)
00582 {
00583    struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
00584    char *buf_copy;
00585    pjsip_dialog *dlg;
00586 
00587    if (!channel) {
00588       ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
00589       return -1;
00590    }
00591 
00592    dlg = channel->session->inv_session->dlg;
00593 
00594    if (ast_strlen_zero(type)) {
00595       ast_log(LOG_WARNING, "You must supply a type field for 'pjsip' information\n");
00596       return -1;
00597    } else if (!strcmp(type, "secure")) {
00598 #ifdef HAVE_PJSIP_GET_DEST_INFO
00599       pjsip_host_info dest;
00600       pj_pool_t *pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "secure-check", 128, 128);
00601       pjsip_get_dest_info(dlg->target, NULL, pool, &dest);
00602       snprintf(buf, buflen, "%d", dest.flag & PJSIP_TRANSPORT_SECURE ? 1 : 0);
00603       pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
00604 #else
00605       ast_log(LOG_WARNING, "Asterisk has been built against a version of pjproject which does not have the required functionality to support the 'secure' argument. Please upgrade to version 2.3 or later.\n");
00606       return -1;
00607 #endif
00608    } else if (!strcmp(type, "target_uri")) {
00609       pjsip_uri_print(PJSIP_URI_IN_REQ_URI, dlg->target, buf, buflen);
00610       buf_copy = ast_strdupa(buf);
00611       ast_escape_quoted(buf_copy, buf, buflen);
00612    } else if (!strcmp(type, "local_uri")) {
00613       pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, dlg->local.info->uri, buf, buflen);
00614       buf_copy = ast_strdupa(buf);
00615       ast_escape_quoted(buf_copy, buf, buflen);
00616    } else if (!strcmp(type, "remote_uri")) {
00617       pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, dlg->remote.info->uri, buf, buflen);
00618       buf_copy = ast_strdupa(buf);
00619       ast_escape_quoted(buf_copy, buf, buflen);
00620    } else if (!strcmp(type, "t38state")) {
00621       ast_copy_string(buf, t38state_to_string[channel->session->t38state], buflen);
00622    } else if (!strcmp(type, "local_addr")) {
00623       RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
00624       struct transport_info_data *transport_data;
00625 
00626       datastore = ast_sip_session_get_datastore(channel->session, "transport_info");
00627       if (!datastore) {
00628          ast_log(AST_LOG_WARNING, "No transport information for channel %s\n", ast_channel_name(chan));
00629          return -1;
00630       }
00631       transport_data = datastore->data;
00632 
00633       if (pj_sockaddr_has_addr(&transport_data->local_addr)) {
00634          pj_sockaddr_print(&transport_data->local_addr, buf, buflen, 3);
00635       }
00636    } else if (!strcmp(type, "remote_addr")) {
00637       RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
00638       struct transport_info_data *transport_data;
00639 
00640       datastore = ast_sip_session_get_datastore(channel->session, "transport_info");
00641       if (!datastore) {
00642          ast_log(AST_LOG_WARNING, "No transport information for channel %s\n", ast_channel_name(chan));
00643          return -1;
00644       }
00645       transport_data = datastore->data;
00646 
00647       if (pj_sockaddr_has_addr(&transport_data->remote_addr)) {
00648          pj_sockaddr_print(&transport_data->remote_addr, buf, buflen, 3);
00649       }
00650    } else {
00651       ast_log(AST_LOG_WARNING, "Unrecognized argument '%s' for 'pjsip' information\n", type);
00652       return -1;
00653    }
00654 
00655    return 0;
00656 }
00657 
00658 /*! \brief Struct used to push function arguments to task processor */
00659 struct pjsip_func_args {
00660    struct ast_channel *chan;
00661    const char *param;
00662    const char *type;
00663    const char *field;
00664    char *buf;
00665    size_t len;
00666    int ret;
00667 };
00668 
00669 /*! \internal \brief Taskprocessor callback that handles the read on a PJSIP thread */
00670 static int read_pjsip(void *data)
00671 {
00672    struct pjsip_func_args *func_args = data;
00673 
00674    if (!strcmp(func_args->param, "rtp")) {
00675       func_args->ret = channel_read_rtp(func_args->chan, func_args->type,
00676                                         func_args->field, func_args->buf,
00677                                         func_args->len);
00678    } else if (!strcmp(func_args->param, "rtcp")) {
00679       func_args->ret = channel_read_rtcp(func_args->chan, func_args->type,
00680                                          func_args->field, func_args->buf,
00681                                          func_args->len);
00682    } else if (!strcmp(func_args->param, "endpoint")) {
00683       struct ast_sip_channel_pvt *pvt = ast_channel_tech_pvt(func_args->chan);
00684 
00685       if (!pvt) {
00686          ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(func_args->chan));
00687          return -1;
00688       }
00689       if (!pvt->session || !pvt->session->endpoint) {
00690          ast_log(AST_LOG_WARNING, "Channel %s has no endpoint!\n", ast_channel_name(func_args->chan));
00691          return -1;
00692       }
00693       snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(pvt->session->endpoint));
00694    } else if (!strcmp(func_args->param, "contact")) {
00695       struct ast_sip_channel_pvt *pvt = ast_channel_tech_pvt(func_args->chan);
00696 
00697       if (!pvt) {
00698          ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(func_args->chan));
00699          return -1;
00700       }
00701       if (!pvt->session || !pvt->session->contact) {
00702          return 0;
00703       }
00704       snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(pvt->session->contact));
00705    } else if (!strcmp(func_args->param, "aor")) {
00706       struct ast_sip_channel_pvt *pvt = ast_channel_tech_pvt(func_args->chan);
00707 
00708       if (!pvt) {
00709          ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(func_args->chan));
00710          return -1;
00711       }
00712       if (!pvt->session || !pvt->session->aor) {
00713          return 0;
00714       }
00715       snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(pvt->session->aor));
00716    } else if (!strcmp(func_args->param, "pjsip")) {
00717       func_args->ret = channel_read_pjsip(func_args->chan, func_args->type,
00718                                           func_args->field, func_args->buf,
00719                                           func_args->len);
00720    } else {
00721       func_args->ret = -1;
00722    }
00723 
00724    return 0;
00725 }
00726 
00727 
00728 int pjsip_acf_channel_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00729 {
00730    struct pjsip_func_args func_args = { 0, };
00731    struct ast_sip_channel_pvt *channel;
00732    char *parse = ast_strdupa(data);
00733 
00734    AST_DECLARE_APP_ARGS(args,
00735       AST_APP_ARG(param);
00736       AST_APP_ARG(type);
00737       AST_APP_ARG(field);
00738    );
00739 
00740    if (!chan) {
00741       ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00742       return -1;
00743    }
00744    channel = ast_channel_tech_pvt(chan);
00745 
00746    /* Check for zero arguments */
00747    if (ast_strlen_zero(parse)) {
00748       ast_log(LOG_ERROR, "Cannot call %s without arguments\n", cmd);
00749       return -1;
00750    }
00751 
00752    AST_STANDARD_APP_ARGS(args, parse);
00753 
00754    /* Sanity check */
00755    if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
00756       ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
00757       return 0;
00758    }
00759 
00760    if (!channel) {
00761       ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
00762       return -1;
00763    }
00764 
00765    memset(buf, 0, len);
00766 
00767    func_args.chan = chan;
00768    func_args.param = args.param;
00769    func_args.type = args.type;
00770    func_args.field = args.field;
00771    func_args.buf = buf;
00772    func_args.len = len;
00773    if (ast_sip_push_task_synchronous(channel->session->serializer, read_pjsip, &func_args)) {
00774       ast_log(LOG_WARNING, "Unable to read properties of channel %s: failed to push task\n", ast_channel_name(chan));
00775       return -1;
00776    }
00777 
00778    return func_args.ret;
00779 }
00780 
00781 int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00782 {
00783    RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
00784    RAII_VAR(struct ast_str *, dial, NULL, ast_free_ptr);
00785    const char *aor_name;
00786    char *rest;
00787 
00788    AST_DECLARE_APP_ARGS(args,
00789       AST_APP_ARG(endpoint_name);
00790       AST_APP_ARG(aor_name);
00791       AST_APP_ARG(request_user);
00792    );
00793 
00794    AST_STANDARD_APP_ARGS(args, data);
00795 
00796    if (ast_strlen_zero(args.endpoint_name)) {
00797       ast_log(LOG_WARNING, "An endpoint name must be specified when using the '%s' dialplan function\n", cmd);
00798       return -1;
00799    } else if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", args.endpoint_name))) {
00800       ast_log(LOG_WARNING, "Specified endpoint '%s' was not found\n", args.endpoint_name);
00801       return -1;
00802    }
00803 
00804    aor_name = S_OR(args.aor_name, endpoint->aors);
00805 
00806    if (ast_strlen_zero(aor_name)) {
00807       ast_log(LOG_WARNING, "No AOR has been provided and no AORs are configured on endpoint '%s'\n", args.endpoint_name);
00808       return -1;
00809    } else if (!(dial = ast_str_create(len))) {
00810       ast_log(LOG_WARNING, "Could not get enough buffer space for dialing contacts\n");
00811       return -1;
00812    } else if (!(rest = ast_strdupa(aor_name))) {
00813       ast_log(LOG_WARNING, "Could not duplicate provided AORs\n");
00814       return -1;
00815    }
00816 
00817    while ((aor_name = strsep(&rest, ","))) {
00818       RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup);
00819       RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
00820       struct ao2_iterator it_contacts;
00821       struct ast_sip_contact *contact;
00822 
00823       if (!aor) {
00824          /* If the AOR provided is not found skip it, there may be more */
00825          continue;
00826       } else if (!(contacts = ast_sip_location_retrieve_aor_contacts(aor))) {
00827          /* No contacts are available, skip it as well */
00828          continue;
00829       } else if (!ao2_container_count(contacts)) {
00830          /* We were given a container but no contacts are in it... */
00831          continue;
00832       }
00833 
00834       it_contacts = ao2_iterator_init(contacts, 0);
00835       for (; (contact = ao2_iterator_next(&it_contacts)); ao2_ref(contact, -1)) {
00836          ast_str_append(&dial, -1, "PJSIP/");
00837 
00838          if (!ast_strlen_zero(args.request_user)) {
00839             ast_str_append(&dial, -1, "%s@", args.request_user);
00840          }
00841          ast_str_append(&dial, -1, "%s/%s&", args.endpoint_name, contact->uri);
00842       }
00843       ao2_iterator_destroy(&it_contacts);
00844    }
00845 
00846    /* Trim the '&' at the end off */
00847    ast_str_truncate(dial, ast_str_strlen(dial) - 1);
00848 
00849    ast_copy_string(buf, ast_str_buffer(dial), len);
00850 
00851    return 0;
00852 }
00853 
00854 static int media_offer_read_av(struct ast_sip_session *session, char *buf,
00855                 size_t len, enum ast_media_type media_type)
00856 {
00857    int i, size = 0;
00858 
00859    for (i = 0; i < ast_format_cap_count(session->req_caps); i++) {
00860       struct ast_format *fmt = ast_format_cap_get_format(session->req_caps, i);
00861 
00862       if (ast_format_get_type(fmt) != media_type) {
00863          ao2_ref(fmt, -1);
00864          continue;
00865       }
00866 
00867       /* add one since we'll include a comma */
00868       size = strlen(ast_format_get_name(fmt)) + 1;
00869       if (len < size) {
00870          ao2_ref(fmt, -1);
00871          break;
00872       }
00873       len -= size;
00874 
00875       /* no reason to use strncat here since we have already ensured buf has
00876                    enough space, so strcat can be safely used */
00877       strcat(buf, ast_format_get_name(fmt));
00878       strcat(buf, ",");
00879 
00880       ao2_ref(fmt, -1);
00881    }
00882 
00883    if (size) {
00884       /* remove the extra comma */
00885       buf[strlen(buf) - 1] = '\0';
00886    }
00887    return 0;
00888 }
00889 
00890 struct media_offer_data {
00891    struct ast_sip_session *session;
00892    enum ast_media_type media_type;
00893    const char *value;
00894 };
00895 
00896 static int media_offer_write_av(void *obj)
00897 {
00898    struct media_offer_data *data = obj;
00899 
00900    ast_format_cap_remove_by_type(data->session->req_caps, data->media_type);
00901    ast_format_cap_update_by_allow_disallow(data->session->req_caps, data->value, 1);
00902 
00903    return 0;
00904 }
00905 
00906 int pjsip_acf_media_offer_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00907 {
00908    struct ast_sip_channel_pvt *channel;
00909 
00910    if (!chan) {
00911       ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00912       return -1;
00913    }
00914 
00915    if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
00916       ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
00917       return -1;
00918    }
00919 
00920    channel = ast_channel_tech_pvt(chan);
00921 
00922    if (!strcmp(data, "audio")) {
00923       return media_offer_read_av(channel->session, buf, len, AST_MEDIA_TYPE_AUDIO);
00924    } else if (!strcmp(data, "video")) {
00925       return media_offer_read_av(channel->session, buf, len, AST_MEDIA_TYPE_VIDEO);
00926    }
00927 
00928    return 0;
00929 }
00930 
00931 int pjsip_acf_media_offer_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00932 {
00933    struct ast_sip_channel_pvt *channel;
00934    struct media_offer_data mdata = {
00935       .value = value
00936    };
00937 
00938    if (!chan) {
00939       ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00940       return -1;
00941    }
00942 
00943    if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
00944       ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
00945       return -1;
00946    }
00947 
00948    channel = ast_channel_tech_pvt(chan);
00949    mdata.session = channel->session;
00950 
00951    if (!strcmp(data, "audio")) {
00952       mdata.media_type = AST_MEDIA_TYPE_AUDIO;
00953    } else if (!strcmp(data, "video")) {
00954       mdata.media_type = AST_MEDIA_TYPE_VIDEO;
00955    }
00956 
00957    return ast_sip_push_task_synchronous(channel->session->serializer, media_offer_write_av, &mdata);
00958 }

Generated on Thu Apr 16 06:27:33 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6