Skip to content
Snippets Groups Projects
chan_pjsip.c 94.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
     * Asterisk -- An open source telephony toolkit.
     *
     * Copyright (C) 2013, Digium, Inc.
     *
     * Joshua Colp <jcolp@digium.com>
     *
     * 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 Joshua Colp <jcolp@digium.com>
     *
    
     * \brief PSJIP SIP Channel Driver
    
     *
     * \ingroup channel_drivers
     */
    
    /*** MODULEINFO
    	<depend>pjproject</depend>
    
    	<depend>res_pjsip</depend>
    	<depend>res_pjsip_session</depend>
    
    	<support_level>core</support_level>
     ***/
    
    #include "asterisk.h"
    
    #include <pjsip.h>
    #include <pjsip_ua.h>
    #include <pjlib.h>
    
    #include "asterisk/lock.h"
    #include "asterisk/channel.h"
    #include "asterisk/module.h"
    #include "asterisk/pbx.h"
    #include "asterisk/rtp_engine.h"
    #include "asterisk/acl.h"
    #include "asterisk/callerid.h"
    #include "asterisk/file.h"
    #include "asterisk/cli.h"
    #include "asterisk/app.h"
    #include "asterisk/musiconhold.h"
    #include "asterisk/causes.h"
    #include "asterisk/taskprocessor.h"
    
    #include "asterisk/dsp.h"
    
    #include "asterisk/stasis_endpoints.h"
    #include "asterisk/stasis_channels.h"
    
    #include "asterisk/indications.h"
    
    #include "asterisk/threadstorage.h"
    
    #include "asterisk/features_config.h"
    #include "asterisk/pickup.h"
    
    #include "asterisk/test.h"
    
    #include "asterisk/res_pjsip.h"
    #include "asterisk/res_pjsip_session.h"
    
    #include "pjsip/include/chan_pjsip.h"
    #include "pjsip/include/dialplan_functions.h"
    
    #include "pjsip/include/cli_functions.h"
    
    AST_THREADSTORAGE(uniqueid_threadbuf);
    #define UNIQUEID_BUFSIZE 256
    
    
    static const char channel_type[] = "PJSIP";
    
    static void chan_pjsip_pvt_dtor(void *obj)
    
    {
    }
    
    /* \brief Asterisk core interaction functions */
    
    static struct ast_channel *chan_pjsip_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
    
    static struct ast_channel *chan_pjsip_request_with_stream_topology(const char *type,
    	struct ast_stream_topology *topology, const struct ast_assigned_ids *assignedids,
    	const struct ast_channel *requestor, const char *data, int *cause);
    
    static int chan_pjsip_sendtext(struct ast_channel *ast, const char *text);
    static int chan_pjsip_digit_begin(struct ast_channel *ast, char digit);
    static int chan_pjsip_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
    static int chan_pjsip_call(struct ast_channel *ast, const char *dest, int timeout);
    static int chan_pjsip_hangup(struct ast_channel *ast);
    static int chan_pjsip_answer(struct ast_channel *ast);
    
    static struct ast_frame *chan_pjsip_read_stream(struct ast_channel *ast);
    
    static int chan_pjsip_write(struct ast_channel *ast, struct ast_frame *f);
    
    static int chan_pjsip_write_stream(struct ast_channel *ast, int stream_num, struct ast_frame *f);
    
    static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
    static int chan_pjsip_transfer(struct ast_channel *ast, const char *target);
    static int chan_pjsip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
    static int chan_pjsip_devicestate(const char *data);
    static int chan_pjsip_queryoption(struct ast_channel *ast, int option, void *data, int *datalen);
    
    static const char *chan_pjsip_get_uniqueid(struct ast_channel *ast);
    
    
    /*! \brief PBX interface structure for channel registration */
    
    struct ast_channel_tech chan_pjsip_tech = {
    
    	.type = channel_type,
    
    	.description = "PJSIP Channel Driver",
    	.requester = chan_pjsip_request,
    
    	.requester_with_stream_topology = chan_pjsip_request_with_stream_topology,
    
    	.send_text = chan_pjsip_sendtext,
    	.send_digit_begin = chan_pjsip_digit_begin,
    	.send_digit_end = chan_pjsip_digit_end,
    	.call = chan_pjsip_call,
    	.hangup = chan_pjsip_hangup,
    	.answer = chan_pjsip_answer,
    
    	.read_stream = chan_pjsip_read_stream,
    
    	.write = chan_pjsip_write,
    
    	.write_stream = chan_pjsip_write_stream,
    	.exception = chan_pjsip_read_stream,
    
    	.indicate = chan_pjsip_indicate,
    	.transfer = chan_pjsip_transfer,
    	.fixup = chan_pjsip_fixup,
    	.devicestate = chan_pjsip_devicestate,
    	.queryoption = chan_pjsip_queryoption,
    
    	.func_channel_read = pjsip_acf_channel_read,
    
    	.get_pvt_uniqueid = chan_pjsip_get_uniqueid,
    
    	.properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
    };
    
    /*! \brief SIP session interaction functions */
    
    static void chan_pjsip_session_begin(struct ast_sip_session *session);
    static void chan_pjsip_session_end(struct ast_sip_session *session);
    static int chan_pjsip_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata);
    static void chan_pjsip_incoming_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata);
    
    
    /*! \brief SIP session supplement structure */
    
    static struct ast_sip_session_supplement chan_pjsip_supplement = {
    
    	.method = "INVITE",
    
    	.priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL,
    
    	.session_begin = chan_pjsip_session_begin,
    	.session_end = chan_pjsip_session_end,
    	.incoming_request = chan_pjsip_incoming_request,
    	.incoming_response = chan_pjsip_incoming_response,
    
    	/* It is important that this supplement runs after media has been negotiated */
    	.response_priority = AST_SIP_SESSION_AFTER_MEDIA,
    
    static int chan_pjsip_incoming_ack(struct ast_sip_session *session, struct pjsip_rx_data *rdata);
    
    static struct ast_sip_session_supplement chan_pjsip_ack_supplement = {
    
    	.method = "ACK",
    
    	.priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL,
    
    	.incoming_request = chan_pjsip_incoming_ack,
    
    };
    
    /*! \brief Function called by RTP engine to get local audio RTP peer */
    
    static enum ast_rtp_glue_result chan_pjsip_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
    
    	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
    
    	struct ast_sip_endpoint *endpoint;
    
    	struct ast_datastore *datastore;
    
    	struct ast_sip_session_media *media;
    
    	if (!channel || !channel->session) {
    		return AST_RTP_GLUE_RESULT_FORBID;
    	}
    
    	/* XXX Getting the first RTP instance for direct media related stuff seems just
    	 * absolutely wrong. But the native RTP bridge knows no other method than single-stream
    	 * for direct media. So this is the best we can do.
    	 */
    	media = channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
    	if (!media || !media->rtp) {
    
    		return AST_RTP_GLUE_RESULT_FORBID;
    	}
    
    
    	datastore = ast_sip_session_get_datastore(channel->session, "t38");
    	if (datastore) {
    		ao2_ref(datastore, -1);
    		return AST_RTP_GLUE_RESULT_FORBID;
    	}
    
    
    	endpoint = channel->session->endpoint;
    
    	ao2_ref(*instance, +1);
    
    	ast_assert(endpoint != NULL);
    
    	if (endpoint->media.rtp.encryption != AST_SIP_MEDIA_ENCRYPT_NONE) {
    
    		return AST_RTP_GLUE_RESULT_FORBID;
    	}
    
    
    	if (endpoint->media.direct_media.enabled) {
    
    		return AST_RTP_GLUE_RESULT_REMOTE;
    	}
    
    	return AST_RTP_GLUE_RESULT_LOCAL;
    }
    
    /*! \brief Function called by RTP engine to get local video RTP peer */
    
    static enum ast_rtp_glue_result chan_pjsip_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
    
    	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
    
    	struct ast_sip_endpoint *endpoint;
    
    	struct ast_sip_session_media *media;
    
    	if (!channel || !channel->session) {
    		return AST_RTP_GLUE_RESULT_FORBID;
    	}
    
    	media = channel->session->active_media_state->default_session[AST_MEDIA_TYPE_VIDEO];
    	if (!media || !media->rtp) {
    
    		return AST_RTP_GLUE_RESULT_FORBID;
    	}
    
    
    	endpoint = channel->session->endpoint;
    
    
    	ao2_ref(*instance, +1);
    
    
    	ast_assert(endpoint != NULL);
    
    	if (endpoint->media.rtp.encryption != AST_SIP_MEDIA_ENCRYPT_NONE) {
    
    		return AST_RTP_GLUE_RESULT_FORBID;
    	}
    
    
    	return AST_RTP_GLUE_RESULT_LOCAL;
    }
    
    /*! \brief Function called by RTP engine to get peer capabilities */
    
    static void chan_pjsip_get_codec(struct ast_channel *chan, struct ast_format_cap *result)
    
    	ast_format_cap_append_from_cap(result, ast_channel_nativeformats(chan), AST_MEDIA_TYPE_UNKNOWN);
    
    /*! \brief Destructor function for \ref transport_info_data */
    static void transport_info_destroy(void *obj)
    {
    	struct transport_info_data *data = obj;
    	ast_free(data);
    }
    
    /*! \brief Datastore used to store local/remote addresses for the
     * INVITE request that created the PJSIP channel */
    static struct ast_datastore_info transport_info = {
    	.type = "chan_pjsip_transport_info",
    	.destroy = transport_info_destroy,
    };
    
    
    static struct ast_datastore_info direct_media_mitigation_info = { };
    
    static int direct_media_mitigate_glare(struct ast_sip_session *session)
    {
    	RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
    
    
    	if (session->endpoint->media.direct_media.glare_mitigation ==
    
    			AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_NONE) {
    		return 0;
    	}
    
    	datastore = ast_sip_session_get_datastore(session, "direct_media_glare_mitigation");
    	if (!datastore) {
    		return 0;
    	}
    
    	/* Removing the datastore ensures we won't try to mitigate glare on subsequent reinvites */
    	ast_sip_session_remove_datastore(session, "direct_media_glare_mitigation");
    
    
    	if ((session->endpoint->media.direct_media.glare_mitigation ==
    
    			AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_OUTGOING &&
    			session->inv_session->role == PJSIP_ROLE_UAC) ||
    
    			(session->endpoint->media.direct_media.glare_mitigation ==
    
    			AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_INCOMING &&
    			session->inv_session->role == PJSIP_ROLE_UAS)) {
    		return 1;
    	}
    
    	return 0;
    }
    
    
    /*! \brief Helper function to find the position for RTCP */
    static int rtp_find_rtcp_fd_position(struct ast_sip_session *session, struct ast_rtp_instance *rtp)
    {
    	int index;
    
    	for (index = 0; index < AST_VECTOR_SIZE(&session->active_media_state->read_callbacks); ++index) {
    		struct ast_sip_session_media_read_callback_state *callback_state =
    			AST_VECTOR_GET_ADDR(&session->active_media_state->read_callbacks, index);
    
    		if (callback_state->fd != ast_rtp_instance_fd(rtp, 1)) {
    			continue;
    		}
    
    		return index;
    	}
    
    	return -1;
    }
    
    
    static int check_for_rtp_changes(struct ast_channel *chan, struct ast_rtp_instance *rtp,
    
    		struct ast_sip_session_media *media, struct ast_sip_session *session)
    
    	int changed = 0, position = -1;
    
    	if (media->rtp) {
    		position = rtp_find_rtcp_fd_position(session, media->rtp);
    	}
    
    
    	if (rtp) {
    		changed = ast_rtp_instance_get_and_cmp_remote_address(rtp, &media->direct_media_addr);
    		if (media->rtp) {
    
    			if (position != -1) {
    				ast_channel_set_fd(chan, position + AST_EXTENDED_FDS, -1);
    			}
    
    			ast_rtp_instance_set_prop(media->rtp, AST_RTP_PROPERTY_RTCP, 0);
    		}
    	} else if (!ast_sockaddr_isnull(&media->direct_media_addr)){
    		ast_sockaddr_setnull(&media->direct_media_addr);
    		changed = 1;
    		if (media->rtp) {
    			ast_rtp_instance_set_prop(media->rtp, AST_RTP_PROPERTY_RTCP, 1);
    
    			if (position != -1) {
    				ast_channel_set_fd(chan, position + AST_EXTENDED_FDS, ast_rtp_instance_fd(media->rtp, 1));
    			}
    
    struct rtp_direct_media_data {
    	struct ast_channel *chan;
    	struct ast_rtp_instance *rtp;
    	struct ast_rtp_instance *vrtp;
    	struct ast_format_cap *cap;
    	struct ast_sip_session *session;
    };
    
    static void rtp_direct_media_data_destroy(void *data)
    {
    	struct rtp_direct_media_data *cdata = data;
    
    	ao2_cleanup(cdata->session);
    	ao2_cleanup(cdata->cap);
    	ao2_cleanup(cdata->vrtp);
    	ao2_cleanup(cdata->rtp);
    	ao2_cleanup(cdata->chan);
    }
    
    static struct rtp_direct_media_data *rtp_direct_media_data_create(
    	struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp,
    	const struct ast_format_cap *cap, struct ast_sip_session *session)
    {
    	struct rtp_direct_media_data *cdata = ao2_alloc(sizeof(*cdata), rtp_direct_media_data_destroy);
    
    	if (!cdata) {
    		return NULL;
    	}
    
    	cdata->chan = ao2_bump(chan);
    	cdata->rtp = ao2_bump(rtp);
    	cdata->vrtp = ao2_bump(vrtp);
    	cdata->cap = ao2_bump((struct ast_format_cap *)cap);
    	cdata->session = ao2_bump(session);
    
    	return cdata;
    }
    
    static int send_direct_media_request(void *data)
    {
    	struct rtp_direct_media_data *cdata = data;
    	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(cdata->chan);
    
    	struct ast_sip_session *session;
    
    	/* XXX In an ideal world each media stream would be direct, but for now preserve behavior
    	 * and connect only the default media sessions for audio and video.
    	 */
    
    
    	/* The channel needs to be locked when checking for RTP changes.
    	 * Otherwise, we could end up destroying an underlying RTCP structure
    	 * at the same time that the channel thread is attempting to read RTCP
    	 */
    	ast_channel_lock(cdata->chan);
    
    	session = channel->session;
    	if (session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]) {
    
    			cdata->chan, cdata->rtp, session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO], session);
    
    	if (session->active_media_state->default_session[AST_MEDIA_TYPE_VIDEO]) {
    
    			cdata->chan, cdata->vrtp, session->active_media_state->default_session[AST_MEDIA_TYPE_VIDEO], session);
    
    	ast_channel_unlock(cdata->chan);
    
    
    	if (direct_media_mitigate_glare(cdata->session)) {
    		ast_debug(4, "Disregarding setting RTP on %s: mitigating re-INVITE glare\n", ast_channel_name(cdata->chan));
    
    		return 0;
    	}
    
    	if (cdata->cap && ast_format_cap_count(cdata->cap) &&
    	    !ast_format_cap_identical(cdata->session->direct_media_cap, cdata->cap)) {
    		ast_format_cap_remove_by_type(cdata->session->direct_media_cap, AST_MEDIA_TYPE_UNKNOWN);
    		ast_format_cap_append_from_cap(cdata->session->direct_media_cap, cdata->cap, AST_MEDIA_TYPE_UNKNOWN);
    		changed = 1;
    	}
    
    	if (changed) {
    		ast_debug(4, "RTP changed on %s; initiating direct media update\n", ast_channel_name(cdata->chan));
    		res = ast_sip_session_refresh(cdata->session, NULL, NULL, NULL,
    
    			cdata->session->endpoint->media.direct_media.method, 1, NULL);
    
    /*! \brief Function called by RTP engine to change where the remote party should send media */
    
    static int chan_pjsip_set_rtp_peer(struct ast_channel *chan,
    
    		struct ast_rtp_instance *rtp,
    		struct ast_rtp_instance *vrtp,
    		struct ast_rtp_instance *tpeer,
    		const struct ast_format_cap *cap,
    		int nat_active)
    {
    
    	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
    	struct ast_sip_session *session = channel->session;
    
    	struct rtp_direct_media_data *cdata;
    
    
    	/* Don't try to do any direct media shenanigans on early bridges */
    
    	if ((rtp || vrtp || tpeer) && !ast_channel_is_bridged(chan)) {
    
    		ast_debug(4, "Disregarding setting RTP on %s: channel is not bridged\n", ast_channel_name(chan));
    
    	if (nat_active && session->endpoint->media.direct_media.disable_on_nat) {
    
    		ast_debug(4, "Disregarding setting RTP on %s: NAT is active\n", ast_channel_name(chan));
    
    	cdata = rtp_direct_media_data_create(chan, rtp, vrtp, cap, session);
    	if (!cdata) {
    
    	if (ast_sip_push_task(session->serializer, send_direct_media_request, cdata)) {
    		ast_log(LOG_ERROR, "Unable to send direct media request for channel %s\n", ast_channel_name(chan));
    		ao2_ref(cdata, -1);
    
    	}
    
    	return 0;
    }
    
    /*! \brief Local glue for interacting with the RTP engine core */
    
    static struct ast_rtp_glue chan_pjsip_rtp_glue = {
    	.type = "PJSIP",
    	.get_rtp_info = chan_pjsip_get_rtp_peer,
    	.get_vrtp_info = chan_pjsip_get_vrtp_peer,
    	.get_codec = chan_pjsip_get_codec,
    	.update_peer = chan_pjsip_set_rtp_peer,
    
    static void set_channel_on_rtp_instance(const struct ast_sip_session *session,
    	const char *channel_id)
    
    	int i;
    
    	for (i = 0; i < AST_VECTOR_SIZE(&session->active_media_state->sessions); ++i) {
    		struct ast_sip_session_media *session_media;
    
    		session_media = AST_VECTOR_GET(&session->active_media_state->sessions, i);
    		if (!session_media || !session_media->rtp) {
    			continue;
    		}
    
    		ast_rtp_instance_set_channel_id(session_media->rtp, channel_id);
    
    }
    
    /*!
     * \brief Determine if a topology is compatible with format capabilities
     *
     * This will return true if ANY formats in the topology are compatible with the format
     * capabilities.
     *
     * XXX When supporting true multistream, we will need to be sure to mark which streams from
     * top1 are compatible with which streams from top2. Then the ones that are not compatible
     * will need to be marked as "removed" so that they are negotiated as expected.
     *
     * \param top Topology
     * \param cap Format capabilities
     * \retval 1 The topology has at least one compatible format
     * \retval 0 The topology has no compatible formats or an error occurred.
     */
    static int compatible_formats_exist(struct ast_stream_topology *top, struct ast_format_cap *cap)
    {
    	struct ast_format_cap *cap_from_top;
    	int res;
    
    	cap_from_top = ast_format_cap_from_stream_topology(top);
    
    	if (!cap_from_top) {
    		return 0;
    
    
    	res = ast_format_cap_iscompatible(cap_from_top, cap);
    	ao2_ref(cap_from_top, -1);
    
    	return res;
    
    /*! \brief Function called to create a new PJSIP Asterisk channel */
    
    static struct ast_channel *chan_pjsip_new(struct ast_sip_session *session, int state, const char *exten, const char *title, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *cid_name)
    
    {
    	struct ast_channel *chan;
    
    	RAII_VAR(struct chan_pjsip_pvt *, pvt, NULL, ao2_cleanup);
    
    	struct ast_sip_channel_pvt *channel;
    
    	struct ast_variable *var;
    
    	struct ast_stream_topology *topology;
    
    	if (!(pvt = ao2_alloc_options(sizeof(*pvt), chan_pjsip_pvt_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK))) {
    
    	chan = ast_channel_alloc_with_endpoint(1, state,
    		S_COR(session->id.number.valid, session->id.number.str, ""),
    		S_COR(session->id.name.valid, session->id.name.str, ""),
    
    		session->endpoint->accountcode,
    		exten, session->endpoint->context,
    		assignedids, requestor, 0,
    
    		session->endpoint->persistent, "PJSIP/%s-%08x",
    		ast_sorcery_object_get_id(session->endpoint),
    		(unsigned) ast_atomic_fetchadd_int((int *) &chan_idx, +1));
    
    	ast_channel_tech_set(chan, &chan_pjsip_tech);
    
    	if (!(channel = ast_sip_channel_pvt_alloc(pvt, session))) {
    
    		ast_channel_unlock(chan);
    
    		ast_hangup(chan);
    		return NULL;
    	}
    
    	ast_channel_tech_pvt_set(chan, channel);
    
    	if (!ast_stream_topology_get_count(session->pending_media_state->topology) ||
    		!compatible_formats_exist(session->pending_media_state->topology, session->endpoint->media.codecs)) {
    		caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
    		if (!caps) {
    			ast_channel_unlock(chan);
    			ast_hangup(chan);
    			return NULL;
    		}
    
    		ast_format_cap_append_from_cap(caps, session->endpoint->media.codecs, AST_MEDIA_TYPE_UNKNOWN);
    
    		topology = ast_stream_topology_clone(session->endpoint->media.topology);
    
    		caps = ast_format_cap_from_stream_topology(session->pending_media_state->topology);
    		topology = ast_stream_topology_clone(session->pending_media_state->topology);
    	}
    
    	if (!topology || !caps) {
    		ao2_cleanup(caps);
    		ast_stream_topology_free(topology);
    		ast_channel_unlock(chan);
    		ast_hangup(chan);
    		return NULL;
    
    	ast_channel_nativeformats_set(chan, caps);
    
    	ast_channel_set_stream_topology(chan, topology);
    
    	if (!ast_format_cap_empty(caps)) {
    
    		fmt = ast_format_cap_get_best_by_type(caps, AST_MEDIA_TYPE_AUDIO);
    		if (!fmt) {
    			/* Since our capabilities aren't empty, this will succeed */
    			fmt = ast_format_cap_get_format(caps, 0);
    		}
    
    		ast_channel_set_writeformat(chan, fmt);
    		ast_channel_set_rawwriteformat(chan, fmt);
    		ast_channel_set_readformat(chan, fmt);
    		ast_channel_set_rawreadformat(chan, fmt);
    		ao2_ref(fmt, -1);
    	}
    
    
    
    	if (state == AST_STATE_RING) {
    		ast_channel_rings_set(chan, 1);
    	}
    
    	ast_channel_adsicpe_set(chan, AST_ADSI_UNAVAILABLE);
    
    
    	ast_party_id_copy(&ast_channel_caller(chan)->id, &session->id);
    	ast_party_id_copy(&ast_channel_caller(chan)->ani, &session->id);
    
    
    	if (!ast_strlen_zero(exten)) {
    		/* Set provided DNID on the new channel. */
    		ast_channel_dialed(chan)->number.str = ast_strdup(exten);
    	}
    
    
    	ast_channel_priority_set(chan, 1);
    
    
    	ast_channel_callgroup_set(chan, session->endpoint->pickup.callgroup);
    	ast_channel_pickupgroup_set(chan, session->endpoint->pickup.pickupgroup);
    
    	ast_channel_named_callgroups_set(chan, session->endpoint->pickup.named_callgroups);
    	ast_channel_named_pickupgroups_set(chan, session->endpoint->pickup.named_pickupgroups);
    
    	if (!ast_strlen_zero(session->endpoint->language)) {
    		ast_channel_language_set(chan, session->endpoint->language);
    	}
    
    	if (!ast_strlen_zero(session->endpoint->zone)) {
    		struct ast_tone_zone *zone = ast_get_indication_zone(session->endpoint->zone);
    		if (!zone) {
    			ast_log(LOG_ERROR, "Unknown country code '%s' for tonezone. Check indications.conf for available country codes.\n", session->endpoint->zone);
    		}
    		ast_channel_zone_set(chan, zone);
    	}
    
    
    	for (var = session->endpoint->channel_vars; var; var = var->next) {
    		char buf[512];
    		pbx_builtin_setvar_helper(chan, var->name, ast_get_encoded_str(
    						  var->value, buf, sizeof(buf)));
    	}
    
    
    	ast_channel_stage_snapshot_done(chan);
    
    	ast_channel_unlock(chan);
    
    
    	set_channel_on_rtp_instance(session, ast_channel_uniqueid(chan));
    
    	return chan;
    }
    
    static int answer(void *data)
    {
    
    	pj_status_t status = PJ_SUCCESS;
    
    	pjsip_tx_data *packet = NULL;
    
    	struct ast_sip_session *session = data;
    
    
    	if (session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
    
    		ast_log(LOG_ERROR, "Session already DISCONNECTED [reason=%d (%s)]\n",
    			session->inv_session->cause,
    			pjsip_get_status_text(session->inv_session->cause)->ptr);
    #ifdef HAVE_PJSIP_INV_SESSION_REF
    		pjsip_inv_dec_ref(session->inv_session);
    #endif
    
    	pjsip_dlg_inc_lock(session->inv_session->dlg);
    	if (session->inv_session->invite_tsx) {
    		status = pjsip_inv_answer(session->inv_session, 200, NULL, NULL, &packet);
    
    	} else {
    		ast_log(LOG_ERROR,"Cannot answer '%s' because there is no associated SIP transaction\n",
    			ast_channel_name(session->channel));
    
    	}
    	pjsip_dlg_dec_lock(session->inv_session->dlg);
    
    	if (status == PJ_SUCCESS && packet) {
    
    		ast_sip_session_send_response(session, packet);
    	}
    
    
    #ifdef HAVE_PJSIP_INV_SESSION_REF
    	pjsip_inv_dec_ref(session->inv_session);
    #endif
    
    
    	if (status != PJ_SUCCESS) {
    		char err[PJ_ERR_MSG_SIZE];
    
    		pj_strerror(status, err, sizeof(err));
    		ast_log(LOG_WARNING,"Cannot answer '%s': %s\n",
    			ast_channel_name(session->channel), err);
    		/*
    		 * Return this value so we can distinguish between this
    		 * failure and the threadpool synchronous push failing.
    		 */
    		return -2;
    	}
    	return 0;
    
    /*! \brief Function called by core when we should answer a PJSIP session */
    static int chan_pjsip_answer(struct ast_channel *ast)
    
    	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast);
    
    
    	if (ast_channel_state(ast) == AST_STATE_UP) {
    		return 0;
    	}
    
    	ast_setstate(ast, AST_STATE_UP);
    
    #ifdef HAVE_PJSIP_INV_SESSION_REF
    	if (pjsip_inv_add_ref(session->inv_session) != PJ_SUCCESS) {
    		ast_log(LOG_ERROR, "Can't increase the session reference counter\n");
    		ao2_ref(session, -1);
    		return -1;
    	}
    #endif
    
    
    	/* the answer task needs to be pushed synchronously otherwise a race condition
    	   can occur between this thread and bridging (specifically when native bridging
    	   attempts to do direct media) */
    	ast_channel_unlock(ast);
    
    	res = ast_sip_push_task_synchronous(session->serializer, answer, session);
    	if (res) {
    		if (res == -1) {
    			ast_log(LOG_ERROR,"Cannot answer '%s': Unable to push answer task to the threadpool.\n",
    				ast_channel_name(session->channel));
    
    #ifdef HAVE_PJSIP_INV_SESSION_REF
    
    			pjsip_inv_dec_ref(session->inv_session);
    
    		ao2_ref(session, -1);
    		ast_channel_lock(ast);
    
    	ao2_ref(session, -1);
    	ast_channel_lock(ast);
    
    /*! \brief Internal helper function called when CNG tone is detected */
    
    static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *session, struct ast_frame *f)
    
    {
    	const char *target_context;
    	int exists;
    
    	dsp_features = ast_dsp_get_features(session->dsp);
    	dsp_features &= ~DSP_FEATURE_FAX_DETECT;
    	if (dsp_features) {
    		ast_dsp_set_features(session->dsp, dsp_features);
    
    	} else {
    		ast_dsp_free(session->dsp);
    		session->dsp = NULL;
    	}
    
    	/* If already executing in the fax extension don't do anything */
    	if (!strcmp(ast_channel_exten(session->channel), "fax")) {
    		return f;
    	}
    
    	target_context = S_OR(ast_channel_macrocontext(session->channel), ast_channel_context(session->channel));
    
    
    	/*
    	 * We need to unlock the channel here because ast_exists_extension has the
    
    	 * potential to start and stop an autoservice on the channel. Such action
    	 * is prone to deadlock if the channel is locked.
    
    	 *
    	 * ast_async_goto() has its own restriction on not holding the channel lock.
    
    	 */
    	ast_channel_unlock(session->channel);
    
    	ast_frfree(f);
    	f = &ast_null_frame;
    
    	exists = ast_exists_extension(session->channel, target_context, "fax", 1,
    		S_COR(ast_channel_caller(session->channel)->id.number.valid,
    			ast_channel_caller(session->channel)->id.number.str, NULL));
    	if (exists) {
    		ast_verb(2, "Redirecting '%s' to fax extension due to CNG detection\n",
    			ast_channel_name(session->channel));
    		pbx_builtin_setvar_helper(session->channel, "FAXEXTEN", ast_channel_exten(session->channel));
    		if (ast_async_goto(session->channel, target_context, "fax", 1)) {
    			ast_log(LOG_ERROR, "Failed to async goto '%s' into fax extension in '%s'\n",
    				ast_channel_name(session->channel), target_context);
    		}
    	} else {
    		ast_log(LOG_NOTICE, "FAX CNG detected on '%s' but no fax extension in '%s'\n",
    			ast_channel_name(session->channel), target_context);
    	}
    
    	ast_channel_lock(session->channel);
    
    /*!
     * \brief Function called by core to read any waiting frames 
     *
     * \note The channel is already locked.
     */
    
    static struct ast_frame *chan_pjsip_read_stream(struct ast_channel *ast)
    
    	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast);
    
    	struct ast_sip_session *session = channel->session;
    	struct ast_sip_session_media_read_callback_state *callback_state;
    
    	struct ast_frame *f;
    
    	int fdno = ast_channel_fdno(ast) - AST_EXTENDED_FDS;
    
    	if (fdno >= AST_VECTOR_SIZE(&session->active_media_state->read_callbacks)) {
    
    		return &ast_null_frame;
    	}
    
    
    	callback_state = AST_VECTOR_GET_ADDR(&session->active_media_state->read_callbacks, fdno);
    	f = callback_state->read_callback(session, callback_state->session);
    
    	if (!f) {
    
    	if (f->frametype != AST_FRAME_VOICE ||
    		callback_state->session != session->active_media_state->default_session[callback_state->session->type]) {
    
    	session = channel->session;
    
    	/*
    	 * Asymmetric RTP only has one native format set at a time.
    	 * Therefore we need to update the native format to the current
    	 * raw read format BEFORE the native format check
    	 */
    
    	if (!session->endpoint->asymmetric_rtp_codec &&
    		ast_format_cmp(ast_channel_rawwriteformat(ast), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
    
    		struct ast_format_cap *caps;
    
    		/* For maximum compatibility we ensure that the formats match that of the received media */
    
    		ast_debug(1, "Oooh, got a frame with format of %s on channel '%s' when we're sending '%s', switching to match\n",
    			ast_format_get_name(f->subclass.format), ast_channel_name(ast),
    			ast_format_get_name(ast_channel_rawwriteformat(ast)));
    
    
    		caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
    		if (caps) {
    			ast_format_cap_append_from_cap(caps, ast_channel_nativeformats(ast), AST_MEDIA_TYPE_UNKNOWN);
    			ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_AUDIO);
    			ast_format_cap_append(caps, f->subclass.format, 0);
    			ast_channel_nativeformats_set(ast, caps);
    			ao2_ref(caps, -1);
    		}
    
    
    		ast_set_write_format_path(ast, ast_channel_writeformat(ast), f->subclass.format);
    
    		ast_set_read_format_path(ast, ast_channel_readformat(ast), f->subclass.format);
    
    
    		if (ast_channel_is_bridged(ast)) {
    			ast_channel_set_unbridged_nolock(ast, 1);
    		}
    	}
    
    
    	if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
    		ast_debug(1, "Oooh, got a frame with format of %s on channel '%s' when it has not been negotiated\n",
    			ast_format_get_name(f->subclass.format), ast_channel_name(ast));
    
    		ast_frfree(f);
    		return &ast_null_frame;
    	}
    
    
    	if (session->dsp) {
    		int dsp_features;
    
    		dsp_features = ast_dsp_get_features(session->dsp);
    		if ((dsp_features & DSP_FEATURE_FAX_DETECT)
    			&& session->endpoint->faxdetect_timeout
    			&& session->endpoint->faxdetect_timeout <= ast_channel_get_up_time(ast)) {
    			dsp_features &= ~DSP_FEATURE_FAX_DETECT;
    			if (dsp_features) {
    				ast_dsp_set_features(session->dsp, dsp_features);
    			} else {
    				ast_dsp_free(session->dsp);
    				session->dsp = NULL;
    			}
    			ast_debug(3, "Channel driver fax CNG detection timeout on %s\n",
    				ast_channel_name(ast));
    		}
    	}
    	if (session->dsp) {
    		f = ast_dsp_process(ast, session->dsp, f);
    
    		if (f && (f->frametype == AST_FRAME_DTMF)) {
    
    			if (f->subclass.integer == 'f') {
    
    				ast_debug(3, "Channel driver fax CNG detected on %s\n",
    					ast_channel_name(ast));
    				f = chan_pjsip_cng_tone_detected(session, f);
    
    			} else {
    				ast_debug(3, "* Detected inband DTMF '%c' on '%s'\n", f->subclass.integer,
    					ast_channel_name(ast));
    			}
    
    static int chan_pjsip_write_stream(struct ast_channel *ast, int stream_num, struct ast_frame *frame)
    
    	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast);
    
    	struct ast_sip_session *session = channel->session;
    	struct ast_sip_session_media *media = NULL;
    
    	/* The core provides a guarantee that the stream will exist when we are called if stream_num is provided */
    	if (stream_num >= 0) {
    		/* What is not guaranteed is that a media session will exist */
    		if (stream_num < AST_VECTOR_SIZE(&channel->session->active_media_state->sessions)) {
    			media = AST_VECTOR_GET(&channel->session->active_media_state->sessions, stream_num);
    		}
    	}
    
    
    	switch (frame->frametype) {
    	case AST_FRAME_VOICE:
    		if (!media) {
    			return 0;
    
    		} else if (media->type != AST_MEDIA_TYPE_AUDIO) {
    			ast_debug(3, "Channel %s stream %d is of type '%s', not audio!\n",
    				ast_channel_name(ast), stream_num, ast_codec_media_type2str(media->type));
    			return 0;
    		} else if (media == channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO] &&
    			ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
    
    			struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
    
    			struct ast_str *write_transpath = ast_str_alloca(256);
    			struct ast_str *read_transpath = ast_str_alloca(256);
    
    
    			ast_log(LOG_WARNING,
    
    				"Channel %s asked to send %s frame when native formats are %s (rd:%s->%s;%s wr:%s->%s;%s)\n",
    				ast_channel_name(ast),
    
    				ast_format_get_name(frame->subclass.format),
    				ast_format_cap_get_names(ast_channel_nativeformats(ast), &cap_buf),
    
    				ast_format_get_name(ast_channel_rawreadformat(ast)),
    
    				ast_format_get_name(ast_channel_readformat(ast)),
    
    				ast_translate_path_to_str(ast_channel_readtrans(ast), &read_transpath),
    				ast_format_get_name(ast_channel_writeformat(ast)),
    				ast_format_get_name(ast_channel_rawwriteformat(ast)),
    				ast_translate_path_to_str(ast_channel_writetrans(ast), &write_transpath));
    
    		} else if (media->write_callback) {
    			res = media->write_callback(session, media, frame);
    
    
    		}
    		break;
    	case AST_FRAME_VIDEO:
    
    		if (!media) {
    			return 0;
    		} else if (media->type != AST_MEDIA_TYPE_VIDEO) {
    			ast_debug(3, "Channel %s stream %d is of type '%s', not video!\n",
    				ast_channel_name(ast), stream_num, ast_codec_media_type2str(media->type));
    			return 0;
    		} else if (media->write_callback) {
    			res = media->write_callback(session, media, frame);
    
    	case AST_FRAME_MODEM:
    
    		if (!media) {
    			return 0;
    		} else if (media->type != AST_MEDIA_TYPE_IMAGE) {
    			ast_debug(3, "Channel %s stream %d is of type '%s', not image!\n",
    				ast_channel_name(ast), stream_num, ast_codec_media_type2str(media->type));
    			return 0;
    		} else if (media->write_callback) {
    			res = media->write_callback(session, media, frame);
    		}
    
    	case AST_FRAME_CNG:
    		break;
    
    		ast_log(LOG_WARNING, "Can't send %u type frames with PJSIP\n", frame->frametype);
    
    static int chan_pjsip_write(struct ast_channel *ast, struct ast_frame *frame)
    {
    	return chan_pjsip_write_stream(ast, -1, frame);
    }
    
    
    /*! \brief Function called by core to change the underlying owner channel */
    
    static int chan_pjsip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
    
    	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(newchan);
    
    	if (channel->session->channel != oldchan) {
    
    	/*
    	 * The masquerade has suspended the channel's session
    	 * serializer so we can safely change it outside of
    	 * the serializer thread.
    	 */
    	channel->session->channel = newchan;
    
    
    	set_channel_on_rtp_instance(channel->session, ast_channel_uniqueid(newchan));