2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2013, Digium, Inc.
6 * Joshua Colp <jcolp@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \author Joshua Colp <jcolp@digium.com>
23 * \brief Gulp SIP Channel Driver
25 * \ingroup channel_drivers
29 <depend>pjproject</depend>
30 <depend>res_sip</depend>
31 <depend>res_sip_session</depend>
32 <support_level>core</support_level>
41 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
43 #include "asterisk/lock.h"
44 #include "asterisk/channel.h"
45 #include "asterisk/module.h"
46 #include "asterisk/pbx.h"
47 #include "asterisk/rtp_engine.h"
48 #include "asterisk/acl.h"
49 #include "asterisk/callerid.h"
50 #include "asterisk/file.h"
51 #include "asterisk/cli.h"
52 #include "asterisk/app.h"
53 #include "asterisk/musiconhold.h"
54 #include "asterisk/causes.h"
55 #include "asterisk/taskprocessor.h"
56 #include "asterisk/stasis_endpoints.h"
57 #include "asterisk/stasis_channels.h"
59 #include "asterisk/res_sip.h"
60 #include "asterisk/res_sip_session.h"
63 <function name="GULP_DIAL_CONTACTS" language="en_US">
65 Return a dial string for dialing all contacts on an AOR.
68 <parameter name="endpoint" required="true">
69 <para>Name of the endpoint</para>
71 <parameter name="aor" required="false">
72 <para>Name of an AOR to use, if not specified the configured AORs on the endpoint are used</para>
74 <parameter name="request_user" required="false">
75 <para>Optional request user to use in the request URI</para>
79 <para>Returns a properly formatted dial string for dialing all contacts on an AOR.</para>
84 static const char desc[] = "Gulp SIP Channel";
85 static const char channel_type[] = "Gulp";
87 static unsigned int chan_idx;
90 * \brief Positions of various media
92 enum sip_session_media_position {
93 /*! \brief First is audio */
95 /*! \brief Second is video */
97 /*! \brief Last is the size for media details */
102 struct ast_sip_session *session;
103 struct ast_sip_session_media *media[SIP_MEDIA_SIZE];
106 static void gulp_pvt_dtor(void *obj)
108 struct gulp_pvt *pvt = obj;
111 ao2_cleanup(pvt->session);
114 for (i = 0; i < SIP_MEDIA_SIZE; ++i) {
115 ao2_cleanup(pvt->media[i]);
116 pvt->media[i] = NULL;
120 /* \brief Asterisk core interaction functions */
121 static struct ast_channel *gulp_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
122 static int gulp_sendtext(struct ast_channel *ast, const char *text);
123 static int gulp_digit_begin(struct ast_channel *ast, char digit);
124 static int gulp_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
125 static int gulp_call(struct ast_channel *ast, const char *dest, int timeout);
126 static int gulp_hangup(struct ast_channel *ast);
127 static int gulp_answer(struct ast_channel *ast);
128 static struct ast_frame *gulp_read(struct ast_channel *ast);
129 static int gulp_write(struct ast_channel *ast, struct ast_frame *f);
130 static int gulp_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
131 static int gulp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
132 static int gulp_devicestate(const char *data);
134 /*! \brief PBX interface structure for channel registration */
135 static struct ast_channel_tech gulp_tech = {
136 .type = channel_type,
137 .description = "Gulp SIP Channel Driver",
138 .requester = gulp_request,
139 .send_text = gulp_sendtext,
140 .send_digit_begin = gulp_digit_begin,
141 .send_digit_end = gulp_digit_end,
143 .hangup = gulp_hangup,
144 .answer = gulp_answer,
147 .write_video = gulp_write,
148 .exception = gulp_read,
149 .indicate = gulp_indicate,
151 .devicestate = gulp_devicestate,
152 .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
155 /*! \brief SIP session interaction functions */
156 static void gulp_session_begin(struct ast_sip_session *session);
157 static void gulp_session_end(struct ast_sip_session *session);
158 static int gulp_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata);
159 static void gulp_incoming_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata);
161 /*! \brief SIP session supplement structure */
162 static struct ast_sip_session_supplement gulp_supplement = {
164 .priority = AST_SIP_SESSION_SUPPLEMENT_PRIORITY_CHANNEL,
165 .session_begin = gulp_session_begin,
166 .session_end = gulp_session_end,
167 .incoming_request = gulp_incoming_request,
168 .incoming_response = gulp_incoming_response,
171 static int gulp_incoming_ack(struct ast_sip_session *session, struct pjsip_rx_data *rdata);
173 static struct ast_sip_session_supplement gulp_ack_supplement = {
175 .priority = AST_SIP_SESSION_SUPPLEMENT_PRIORITY_CHANNEL,
176 .incoming_request = gulp_incoming_ack,
179 /*! \brief Dialplan function for constructing a dial string for calling all contacts */
180 static int gulp_dial_contacts(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
182 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
183 RAII_VAR(struct ast_str *, dial, NULL, ast_free_ptr);
184 const char *aor_name;
187 AST_DECLARE_APP_ARGS(args,
188 AST_APP_ARG(endpoint_name);
189 AST_APP_ARG(aor_name);
190 AST_APP_ARG(request_user);
193 AST_STANDARD_APP_ARGS(args, data);
195 if (ast_strlen_zero(args.endpoint_name)) {
196 ast_log(LOG_WARNING, "An endpoint name must be specified when using the '%s' dialplan function\n", cmd);
198 } else if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", args.endpoint_name))) {
199 ast_log(LOG_WARNING, "Specified endpoint '%s' was not found\n", args.endpoint_name);
203 aor_name = S_OR(args.aor_name, endpoint->aors);
205 if (ast_strlen_zero(aor_name)) {
206 ast_log(LOG_WARNING, "No AOR has been provided and no AORs are configured on endpoint '%s'\n", args.endpoint_name);
208 } else if (!(dial = ast_str_create(len))) {
209 ast_log(LOG_WARNING, "Could not get enough buffer space for dialing contacts\n");
211 } else if (!(rest = ast_strdupa(aor_name))) {
212 ast_log(LOG_WARNING, "Could not duplicate provided AORs\n");
216 while ((aor_name = strsep(&rest, ","))) {
217 RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup);
218 RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
219 struct ao2_iterator it_contacts;
220 struct ast_sip_contact *contact;
223 /* If the AOR provided is not found skip it, there may be more */
225 } else if (!(contacts = ast_sip_location_retrieve_aor_contacts(aor))) {
226 /* No contacts are available, skip it as well */
228 } else if (!ao2_container_count(contacts)) {
229 /* We were given a container but no contacts are in it... */
233 it_contacts = ao2_iterator_init(contacts, 0);
234 for (; (contact = ao2_iterator_next(&it_contacts)); ao2_ref(contact, -1)) {
235 ast_str_append(&dial, -1, "Gulp/");
237 if (!ast_strlen_zero(args.request_user)) {
238 ast_str_append(&dial, -1, "%s@", args.request_user);
240 ast_str_append(&dial, -1, "%s/%s&", args.endpoint_name, contact->uri);
242 ao2_iterator_destroy(&it_contacts);
245 /* Trim the '&' at the end off */
246 ast_str_truncate(dial, ast_str_strlen(dial) - 1);
248 ast_copy_string(buf, ast_str_buffer(dial), len);
253 static struct ast_custom_function gulp_dial_contacts_function = {
254 .name = "GULP_DIAL_CONTACTS",
255 .read = gulp_dial_contacts,
258 /*! \brief Function called by RTP engine to get local audio RTP peer */
259 static enum ast_rtp_glue_result gulp_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
261 struct gulp_pvt *pvt = ast_channel_tech_pvt(chan);
262 struct ast_sip_endpoint *endpoint;
264 if (!pvt || !pvt->session || !pvt->media[SIP_MEDIA_AUDIO]->rtp) {
265 return AST_RTP_GLUE_RESULT_FORBID;
268 endpoint = pvt->session->endpoint;
270 *instance = pvt->media[SIP_MEDIA_AUDIO]->rtp;
271 ao2_ref(*instance, +1);
273 ast_assert(endpoint != NULL);
274 if (endpoint->direct_media) {
275 return AST_RTP_GLUE_RESULT_REMOTE;
278 return AST_RTP_GLUE_RESULT_LOCAL;
281 /*! \brief Function called by RTP engine to get local video RTP peer */
282 static enum ast_rtp_glue_result gulp_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
284 struct gulp_pvt *pvt = ast_channel_tech_pvt(chan);
286 if (!pvt || !pvt->session || !pvt->media[SIP_MEDIA_VIDEO]->rtp) {
287 return AST_RTP_GLUE_RESULT_FORBID;
290 *instance = pvt->media[SIP_MEDIA_VIDEO]->rtp;
291 ao2_ref(*instance, +1);
293 return AST_RTP_GLUE_RESULT_LOCAL;
296 /*! \brief Function called by RTP engine to get peer capabilities */
297 static void gulp_get_codec(struct ast_channel *chan, struct ast_format_cap *result)
299 struct gulp_pvt *pvt = ast_channel_tech_pvt(chan);
301 ast_format_cap_copy(result, pvt->session->endpoint->codecs);
304 static int send_direct_media_request(void *data)
306 RAII_VAR(struct ast_sip_session *, session, data, ao2_cleanup);
308 return ast_sip_session_refresh(session, NULL, NULL, session->endpoint->direct_media_method, 1);
311 static struct ast_datastore_info direct_media_mitigation_info = { };
313 static int direct_media_mitigate_glare(struct ast_sip_session *session)
315 RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
317 if (session->endpoint->direct_media_glare_mitigation ==
318 AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_NONE) {
322 datastore = ast_sip_session_get_datastore(session, "direct_media_glare_mitigation");
327 /* Removing the datastore ensures we won't try to mitigate glare on subsequent reinvites */
328 ast_sip_session_remove_datastore(session, "direct_media_glare_mitigation");
330 if ((session->endpoint->direct_media_glare_mitigation ==
331 AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_OUTGOING &&
332 session->inv_session->role == PJSIP_ROLE_UAC) ||
333 (session->endpoint->direct_media_glare_mitigation ==
334 AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_INCOMING &&
335 session->inv_session->role == PJSIP_ROLE_UAS)) {
342 static int check_for_rtp_changes(struct ast_channel *chan, struct ast_rtp_instance *rtp,
343 struct ast_sip_session_media *media, int rtcp_fd)
348 changed = ast_rtp_instance_get_and_cmp_remote_address(rtp, &media->direct_media_addr);
350 ast_channel_set_fd(chan, rtcp_fd, -1);
351 ast_rtp_instance_set_prop(media->rtp, AST_RTP_PROPERTY_RTCP, 0);
353 } else if (!ast_sockaddr_isnull(&media->direct_media_addr)){
354 ast_sockaddr_setnull(&media->direct_media_addr);
357 ast_rtp_instance_set_prop(media->rtp, AST_RTP_PROPERTY_RTCP, 1);
358 ast_channel_set_fd(chan, rtcp_fd, ast_rtp_instance_fd(media->rtp, 1));
365 /*! \brief Function called by RTP engine to change where the remote party should send media */
366 static int gulp_set_rtp_peer(struct ast_channel *chan,
367 struct ast_rtp_instance *rtp,
368 struct ast_rtp_instance *vrtp,
369 struct ast_rtp_instance *tpeer,
370 const struct ast_format_cap *cap,
373 struct gulp_pvt *pvt = ast_channel_tech_pvt(chan);
374 struct ast_sip_session *session = pvt->session;
377 /* BUGBUG - ast_bridged_channel will always return NULL, meaning direct media will never occur */
378 /* Don't try to do any direct media shenanigans on early bridges */
379 if ((rtp || vrtp || tpeer) && !ast_bridged_channel(chan)) {
383 if (nat_active && session->endpoint->disable_direct_media_on_nat) {
387 if (pvt->media[SIP_MEDIA_AUDIO]) {
388 changed |= check_for_rtp_changes(chan, rtp, pvt->media[SIP_MEDIA_AUDIO], 1);
390 if (pvt->media[SIP_MEDIA_VIDEO]) {
391 changed |= check_for_rtp_changes(chan, vrtp, pvt->media[SIP_MEDIA_VIDEO], 3);
394 if (direct_media_mitigate_glare(session)) {
398 if (cap && !ast_format_cap_is_empty(cap) && !ast_format_cap_identical(session->direct_media_cap, cap)) {
399 ast_format_cap_copy(session->direct_media_cap, cap);
404 ao2_ref(session, +1);
405 ast_sip_push_task(session->serializer, send_direct_media_request, session);
411 /*! \brief Local glue for interacting with the RTP engine core */
412 static struct ast_rtp_glue gulp_rtp_glue = {
414 .get_rtp_info = gulp_get_rtp_peer,
415 .get_vrtp_info = gulp_get_vrtp_peer,
416 .get_codec = gulp_get_codec,
417 .update_peer = gulp_set_rtp_peer,
420 /*! \brief Function called to create a new Gulp Asterisk channel */
421 static struct ast_channel *gulp_new(struct ast_sip_session *session, int state, const char *exten, const char *title, const char *linkedid, const char *cid_name)
423 struct ast_channel *chan;
424 struct ast_format fmt;
425 struct gulp_pvt *pvt;
427 if (!(pvt = ao2_alloc(sizeof(*pvt), gulp_pvt_dtor))) {
431 if (!(chan = ast_channel_alloc(1, state, S_OR(session->id.number.str, ""), S_OR(session->id.name.str, ""), "", "", "", linkedid, 0, "Gulp/%s-%08x", ast_sorcery_object_get_id(session->endpoint),
432 ast_atomic_fetchadd_int((int *)&chan_idx, +1)))) {
437 ast_channel_tech_set(chan, &gulp_tech);
439 ao2_ref(session, +1);
440 pvt->session = session;
441 /* If res_sip_session is ever updated to create/destroy ast_sip_session_media
442 * during a call such as if multiple same-type stream support is introduced,
443 * these will need to be recaptured as well */
444 pvt->media[SIP_MEDIA_AUDIO] = ao2_find(session->media, "audio", OBJ_KEY);
445 pvt->media[SIP_MEDIA_VIDEO] = ao2_find(session->media, "video", OBJ_KEY);
446 ast_channel_tech_pvt_set(chan, pvt);
448 if (ast_format_cap_is_empty(session->req_caps) || !ast_format_cap_has_joint(session->req_caps, session->endpoint->codecs)) {
449 ast_format_cap_copy(ast_channel_nativeformats(chan), session->endpoint->codecs);
451 ast_format_cap_copy(ast_channel_nativeformats(chan), session->req_caps);
454 ast_codec_choose(&session->endpoint->prefs, ast_channel_nativeformats(chan), 1, &fmt);
455 ast_format_copy(ast_channel_writeformat(chan), &fmt);
456 ast_format_copy(ast_channel_rawwriteformat(chan), &fmt);
457 ast_format_copy(ast_channel_readformat(chan), &fmt);
458 ast_format_copy(ast_channel_rawreadformat(chan), &fmt);
460 if (state == AST_STATE_RING) {
461 ast_channel_rings_set(chan, 1);
464 ast_channel_adsicpe_set(chan, AST_ADSI_UNAVAILABLE);
466 ast_channel_context_set(chan, session->endpoint->context);
467 ast_channel_exten_set(chan, S_OR(exten, "s"));
468 ast_channel_priority_set(chan, 1);
470 ast_endpoint_add_channel(session->endpoint->persistent, chan);
475 static int answer(void *data)
478 pjsip_tx_data *packet;
479 struct ast_sip_session *session = data;
481 if ((status = pjsip_inv_answer(session->inv_session, 200, NULL, NULL, &packet)) == PJ_SUCCESS) {
482 ast_sip_session_send_response(session, packet);
485 ao2_ref(session, -1);
487 return (status == PJ_SUCCESS) ? 0 : -1;
490 /*! \brief Function called by core when we should answer a Gulp session */
491 static int gulp_answer(struct ast_channel *ast)
493 struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
494 struct ast_sip_session *session = pvt->session;
496 if (ast_channel_state(ast) == AST_STATE_UP) {
500 ast_setstate(ast, AST_STATE_UP);
502 ao2_ref(session, +1);
503 if (ast_sip_push_task(session->serializer, answer, session)) {
504 ast_log(LOG_WARNING, "Unable to push answer task to the threadpool. Cannot answer call\n");
505 ao2_cleanup(session);
512 /*! \brief Function called by core to read any waiting frames */
513 static struct ast_frame *gulp_read(struct ast_channel *ast)
515 struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
517 struct ast_sip_session_media *media = NULL;
519 int fdno = ast_channel_fdno(ast);
523 media = pvt->media[SIP_MEDIA_AUDIO];
526 media = pvt->media[SIP_MEDIA_AUDIO];
530 media = pvt->media[SIP_MEDIA_VIDEO];
533 media = pvt->media[SIP_MEDIA_VIDEO];
538 if (!media || !media->rtp) {
539 return &ast_null_frame;
542 f = ast_rtp_instance_read(media->rtp, rtcp);
544 if (f && f->frametype == AST_FRAME_VOICE) {
545 if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &f->subclass.format))) {
546 ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(&f->subclass.format));
547 ast_format_cap_set(ast_channel_nativeformats(ast), &f->subclass.format);
548 ast_set_read_format(ast, ast_channel_readformat(ast));
549 ast_set_write_format(ast, ast_channel_writeformat(ast));
556 /*! \brief Function called by core to write frames */
557 static int gulp_write(struct ast_channel *ast, struct ast_frame *frame)
559 struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
560 struct ast_sip_session_media *media;
563 switch (frame->frametype) {
564 case AST_FRAME_VOICE:
565 media = pvt->media[SIP_MEDIA_AUDIO];
570 if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
574 "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
575 ast_getformatname(&frame->subclass.format),
576 ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)),
577 ast_getformatname(ast_channel_readformat(ast)),
578 ast_getformatname(ast_channel_writeformat(ast)));
582 res = ast_rtp_instance_write(media->rtp, frame);
585 case AST_FRAME_VIDEO:
586 if ((media = pvt->media[SIP_MEDIA_VIDEO]) && media->rtp) {
587 res = ast_rtp_instance_write(media->rtp, frame);
591 ast_log(LOG_WARNING, "Can't send %d type frames with Gulp\n", frame->frametype);
599 struct ast_sip_session *session;
600 struct ast_channel *chan;
603 static int fixup(void *data)
605 struct fixup_data *fix_data = data;
607 fix_data->session->channel = fix_data->chan;
612 /*! \brief Function called by core to change the underlying owner channel */
613 static int gulp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
615 struct gulp_pvt *pvt = ast_channel_tech_pvt(newchan);
616 struct ast_sip_session *session = pvt->session;
617 struct fixup_data fix_data;
619 fix_data.session = session;
620 fix_data.chan = newchan;
622 if (session->channel != oldchan) {
626 if (ast_sip_push_task_synchronous(session->serializer, fixup, &fix_data)) {
627 ast_log(LOG_WARNING, "Unable to perform channel fixup\n");
634 /*! \brief Function called to get the device state of an endpoint */
635 static int gulp_devicestate(const char *data)
637 RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", data), ao2_cleanup);
638 enum ast_device_state state = AST_DEVICE_UNKNOWN;
639 RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot, NULL, ao2_cleanup);
640 RAII_VAR(struct stasis_caching_topic *, caching_topic, NULL, ao2_cleanup);
641 struct ast_devstate_aggregate aggregate;
645 return AST_DEVICE_INVALID;
648 endpoint_snapshot = ast_endpoint_latest_snapshot(ast_endpoint_get_tech(endpoint->persistent),
649 ast_endpoint_get_resource(endpoint->persistent), 1);
651 if (endpoint_snapshot->state == AST_ENDPOINT_OFFLINE) {
652 state = AST_DEVICE_UNAVAILABLE;
653 } else if (endpoint_snapshot->state == AST_ENDPOINT_ONLINE) {
654 state = AST_DEVICE_NOT_INUSE;
657 if (!endpoint_snapshot->num_channels || !(caching_topic = ast_channel_topic_all_cached())) {
661 ast_devstate_aggregate_init(&aggregate);
663 ao2_ref(caching_topic, +1);
665 for (num = 0; num < endpoint_snapshot->num_channels; num++) {
666 RAII_VAR(struct stasis_message *, msg, stasis_cache_get_extended(caching_topic, ast_channel_snapshot_type(),
667 endpoint_snapshot->channel_ids[num], 1), ao2_cleanup);
668 struct ast_channel_snapshot *snapshot;
674 snapshot = stasis_message_data(msg);
676 if (snapshot->state == AST_STATE_DOWN) {
677 ast_devstate_aggregate_add(&aggregate, AST_DEVICE_NOT_INUSE);
678 } else if (snapshot->state == AST_STATE_RINGING) {
679 ast_devstate_aggregate_add(&aggregate, AST_DEVICE_RINGING);
680 } else if ((snapshot->state == AST_STATE_UP) || (snapshot->state == AST_STATE_RING) ||
681 (snapshot->state == AST_STATE_BUSY)) {
682 ast_devstate_aggregate_add(&aggregate, AST_DEVICE_INUSE);
687 if (endpoint->devicestate_busy_at && (inuse == endpoint->devicestate_busy_at)) {
688 state = AST_DEVICE_BUSY;
689 } else if (ast_devstate_aggregate_result(&aggregate) != AST_DEVICE_INVALID) {
690 state = ast_devstate_aggregate_result(&aggregate);
696 struct indicate_data {
697 struct ast_sip_session *session;
704 static void indicate_data_destroy(void *obj)
706 struct indicate_data *ind_data = obj;
708 ast_free(ind_data->frame_data);
709 ao2_ref(ind_data->session, -1);
712 static struct indicate_data *indicate_data_alloc(struct ast_sip_session *session,
713 int condition, int response_code, const void *frame_data, size_t datalen)
715 struct indicate_data *ind_data = ao2_alloc(sizeof(*ind_data), indicate_data_destroy);
721 ind_data->frame_data = ast_malloc(datalen);
722 if (!ind_data->frame_data) {
723 ao2_ref(ind_data, -1);
727 memcpy(ind_data->frame_data, frame_data, datalen);
728 ind_data->datalen = datalen;
729 ind_data->condition = condition;
730 ind_data->response_code = response_code;
731 ao2_ref(session, +1);
732 ind_data->session = session;
737 static int indicate(void *data)
739 pjsip_tx_data *packet = NULL;
740 struct indicate_data *ind_data = data;
741 struct ast_sip_session *session = ind_data->session;
742 int response_code = ind_data->response_code;
744 if (pjsip_inv_answer(session->inv_session, response_code, NULL, NULL, &packet) == PJ_SUCCESS) {
745 ast_sip_session_send_response(session, packet);
748 ao2_ref(ind_data, -1);
753 /*! \brief Send SIP INFO with video update request */
754 static int transmit_info_with_vidupdate(void *data)
757 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n"
758 " <media_control>\r\n"
759 " <vc_primitive>\r\n"
761 " <picture_fast_update/>\r\n"
763 " </vc_primitive>\r\n"
764 " </media_control>\r\n";
766 const struct ast_sip_body body = {
767 .type = "application",
768 .subtype = "media_control+xml",
772 struct ast_sip_session *session = data;
773 struct pjsip_tx_data *tdata;
775 if (ast_sip_create_request("INFO", session->inv_session->dlg, session->endpoint, NULL, &tdata)) {
776 ast_log(LOG_ERROR, "Could not create text video update INFO request\n");
779 if (ast_sip_add_body(tdata, &body)) {
780 ast_log(LOG_ERROR, "Could not add body to text video update INFO request\n");
783 ast_sip_session_send_request(session, tdata);
788 /*! \brief Function called by core to ask the channel to indicate some sort of condition */
789 static int gulp_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
791 struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
792 struct ast_sip_session *session = pvt->session;
793 struct ast_sip_session_media *media;
794 int response_code = 0;
798 case AST_CONTROL_RINGING:
799 if (ast_channel_state(ast) == AST_STATE_RING) {
804 ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "Gulp/%s", ast_sorcery_object_get_id(session->endpoint));
806 case AST_CONTROL_BUSY:
807 if (ast_channel_state(ast) != AST_STATE_UP) {
813 case AST_CONTROL_CONGESTION:
814 if (ast_channel_state(ast) != AST_STATE_UP) {
820 case AST_CONTROL_INCOMPLETE:
821 if (ast_channel_state(ast) != AST_STATE_UP) {
827 case AST_CONTROL_PROCEEDING:
828 if (ast_channel_state(ast) != AST_STATE_UP) {
834 case AST_CONTROL_PROGRESS:
835 if (ast_channel_state(ast) != AST_STATE_UP) {
841 case AST_CONTROL_VIDUPDATE:
842 media = pvt->media[SIP_MEDIA_VIDEO];
843 if (media && media->rtp) {
844 ast_sip_push_task(session->serializer, transmit_info_with_vidupdate, session);
848 case AST_CONTROL_UPDATE_RTP_PEER:
849 case AST_CONTROL_PVT_CAUSE_CODE:
851 case AST_CONTROL_HOLD:
852 ast_moh_start(ast, data, NULL);
854 case AST_CONTROL_UNHOLD:
857 case AST_CONTROL_SRCUPDATE:
859 case AST_CONTROL_SRCCHANGE:
865 ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", condition);
870 if (!res && response_code) {
871 struct indicate_data *ind_data = indicate_data_alloc(session, condition, response_code, data, datalen);
873 res = ast_sip_push_task(session->serializer, indicate, ind_data);
875 ast_log(LOG_NOTICE, "Cannot send response code %d to endpoint %s. Could not queue task properly\n",
876 response_code, ast_sorcery_object_get_id(session->endpoint));
877 ao2_cleanup(ind_data);
887 /*! \brief Function called by core to start a DTMF digit */
888 static int gulp_digit_begin(struct ast_channel *chan, char digit)
890 struct gulp_pvt *pvt = ast_channel_tech_pvt(chan);
891 struct ast_sip_session *session = pvt->session;
892 struct ast_sip_session_media *media = pvt->media[SIP_MEDIA_AUDIO];
895 switch (session->endpoint->dtmf) {
896 case AST_SIP_DTMF_RFC_4733:
897 if (!media || !media->rtp) {
901 ast_rtp_instance_dtmf_begin(media->rtp, digit);
902 case AST_SIP_DTMF_NONE:
904 case AST_SIP_DTMF_INBAND:
914 struct info_dtmf_data {
915 struct ast_sip_session *session;
917 unsigned int duration;
920 static void info_dtmf_data_destroy(void *obj)
922 struct info_dtmf_data *dtmf_data = obj;
923 ao2_ref(dtmf_data->session, -1);
926 static struct info_dtmf_data *info_dtmf_data_alloc(struct ast_sip_session *session, char digit, unsigned int duration)
928 struct info_dtmf_data *dtmf_data = ao2_alloc(sizeof(*dtmf_data), info_dtmf_data_destroy);
932 ao2_ref(session, +1);
933 dtmf_data->session = session;
934 dtmf_data->digit = digit;
935 dtmf_data->duration = duration;
939 static int transmit_info_dtmf(void *data)
941 RAII_VAR(struct info_dtmf_data *, dtmf_data, data, ao2_cleanup);
943 struct ast_sip_session *session = dtmf_data->session;
944 struct pjsip_tx_data *tdata;
946 RAII_VAR(struct ast_str *, body_text, NULL, ast_free_ptr);
948 struct ast_sip_body body = {
949 .type = "application",
950 .subtype = "dtmf-relay",
953 if (!(body_text = ast_str_create(32))) {
954 ast_log(LOG_ERROR, "Could not allocate buffer for INFO DTMF.\n");
957 ast_str_set(&body_text, 0, "Signal=%c\r\nDuration=%u\r\n", dtmf_data->digit, dtmf_data->duration);
959 body.body_text = ast_str_buffer(body_text);
961 if (ast_sip_create_request("INFO", session->inv_session->dlg, session->endpoint, NULL, &tdata)) {
962 ast_log(LOG_ERROR, "Could not create DTMF INFO request\n");
965 if (ast_sip_add_body(tdata, &body)) {
966 ast_log(LOG_ERROR, "Could not add body to DTMF INFO request\n");
967 pjsip_tx_data_dec_ref(tdata);
970 ast_sip_session_send_request(session, tdata);
975 /*! \brief Function called by core to stop a DTMF digit */
976 static int gulp_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
978 struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
979 struct ast_sip_session *session = pvt->session;
980 struct ast_sip_session_media *media = pvt->media[SIP_MEDIA_AUDIO];
983 switch (session->endpoint->dtmf) {
984 case AST_SIP_DTMF_INFO:
986 struct info_dtmf_data *dtmf_data = info_dtmf_data_alloc(session, digit, duration);
992 if (ast_sip_push_task(session->serializer, transmit_info_dtmf, dtmf_data)) {
993 ast_log(LOG_WARNING, "Error sending DTMF via INFO.\n");
994 ao2_cleanup(dtmf_data);
999 case AST_SIP_DTMF_RFC_4733:
1000 if (!media || !media->rtp) {
1004 ast_rtp_instance_dtmf_end_with_duration(media->rtp, digit, duration);
1005 case AST_SIP_DTMF_NONE:
1007 case AST_SIP_DTMF_INBAND:
1015 static int call(void *data)
1017 pjsip_tx_data *packet;
1018 struct ast_sip_session *session = data;
1020 if (pjsip_inv_invite(session->inv_session, &packet) != PJ_SUCCESS) {
1021 ast_queue_hangup(session->channel);
1023 ast_sip_session_send_request(session, packet);
1026 ao2_ref(session, -1);
1031 /*! \brief Function called by core to actually start calling a remote party */
1032 static int gulp_call(struct ast_channel *ast, const char *dest, int timeout)
1034 struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
1035 struct ast_sip_session *session = pvt->session;
1037 ao2_ref(session, +1);
1038 if (ast_sip_push_task(session->serializer, call, session)) {
1039 ast_log(LOG_WARNING, "Error attempting to place outbound call to call '%s'\n", dest);
1040 ao2_cleanup(session);
1047 /*! \brief Internal function which translates from Asterisk cause codes to SIP response codes */
1048 static int hangup_cause2sip(int cause)
1051 case AST_CAUSE_UNALLOCATED: /* 1 */
1052 case AST_CAUSE_NO_ROUTE_DESTINATION: /* 3 IAX2: Can't find extension in context */
1053 case AST_CAUSE_NO_ROUTE_TRANSIT_NET: /* 2 */
1055 case AST_CAUSE_CONGESTION: /* 34 */
1056 case AST_CAUSE_SWITCH_CONGESTION: /* 42 */
1058 case AST_CAUSE_NO_USER_RESPONSE: /* 18 */
1060 case AST_CAUSE_NO_ANSWER: /* 19 */
1061 case AST_CAUSE_UNREGISTERED: /* 20 */
1063 case AST_CAUSE_CALL_REJECTED: /* 21 */
1065 case AST_CAUSE_NUMBER_CHANGED: /* 22 */
1067 case AST_CAUSE_NORMAL_UNSPECIFIED: /* 31 */
1069 case AST_CAUSE_INVALID_NUMBER_FORMAT:
1071 case AST_CAUSE_USER_BUSY:
1073 case AST_CAUSE_FAILURE:
1075 case AST_CAUSE_FACILITY_REJECTED: /* 29 */
1077 case AST_CAUSE_CHAN_NOT_IMPLEMENTED:
1079 case AST_CAUSE_DESTINATION_OUT_OF_ORDER:
1081 case AST_CAUSE_BEARERCAPABILITY_NOTAVAIL: /* Can't find codec to connect to host */
1083 case AST_CAUSE_INTERWORKING: /* Unspecified Interworking issues */
1085 case AST_CAUSE_NOTDEFINED:
1087 ast_debug(1, "AST hangup cause %d (no match found in PJSIP)\n", cause);
1095 struct hangup_data {
1097 struct ast_channel *chan;
1100 static void hangup_data_destroy(void *obj)
1102 struct hangup_data *h_data = obj;
1104 h_data->chan = ast_channel_unref(h_data->chan);
1107 static struct hangup_data *hangup_data_alloc(int cause, struct ast_channel *chan)
1109 struct hangup_data *h_data = ao2_alloc(sizeof(*h_data), hangup_data_destroy);
1115 h_data->cause = cause;
1116 h_data->chan = ast_channel_ref(chan);
1121 static int hangup(void *data)
1124 pjsip_tx_data *packet = NULL;
1125 struct hangup_data *h_data = data;
1126 struct ast_channel *ast = h_data->chan;
1127 struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
1128 struct ast_sip_session *session = pvt->session;
1129 int cause = h_data->cause;
1131 if (((status = pjsip_inv_end_session(session->inv_session, cause ? cause : 603, NULL, &packet)) == PJ_SUCCESS) && packet) {
1132 if (packet->msg->type == PJSIP_RESPONSE_MSG) {
1133 ast_sip_session_send_response(session, packet);
1135 ast_sip_session_send_request(session, packet);
1139 session->channel = NULL;
1140 ast_channel_tech_pvt_set(ast, NULL);
1143 ao2_cleanup(h_data);
1148 /*! \brief Function called by core to hang up a Gulp session */
1149 static int gulp_hangup(struct ast_channel *ast)
1151 struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
1152 struct ast_sip_session *session = pvt->session;
1153 int cause = hangup_cause2sip(ast_channel_hangupcause(session->channel));
1154 struct hangup_data *h_data = hangup_data_alloc(cause, ast);
1160 if (ast_sip_push_task(session->serializer, hangup, h_data)) {
1161 ast_log(LOG_WARNING, "Unable to push hangup task to the threadpool. Expect bad things\n");
1168 /* Go ahead and do our cleanup of the session and channel even if we're not going
1169 * to be able to send our SIP request/response
1171 ao2_cleanup(h_data);
1172 session->channel = NULL;
1173 ast_channel_tech_pvt_set(ast, NULL);
1180 struct request_data {
1181 struct ast_sip_session *session;
1182 struct ast_format_cap *caps;
1187 static int request(void *obj)
1189 struct request_data *req_data = obj;
1190 struct ast_sip_session *session = NULL;
1191 char *tmp = ast_strdupa(req_data->dest), *endpoint_name = NULL, *request_user = NULL;
1192 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
1194 AST_DECLARE_APP_ARGS(args,
1195 AST_APP_ARG(endpoint);
1199 if (ast_strlen_zero(tmp)) {
1200 ast_log(LOG_ERROR, "Unable to create Gulp channel with empty destination\n");
1201 req_data->cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1205 AST_NONSTANDARD_APP_ARGS(args, tmp, '/');
1207 /* If a request user has been specified extract it from the endpoint name portion */
1208 if ((endpoint_name = strchr(args.endpoint, '@'))) {
1209 request_user = args.endpoint;
1210 *endpoint_name++ = '\0';
1212 endpoint_name = args.endpoint;
1215 if (ast_strlen_zero(endpoint_name)) {
1216 ast_log(LOG_ERROR, "Unable to create Gulp channel with empty endpoint name\n");
1217 req_data->cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1218 } else if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name))) {
1219 ast_log(LOG_ERROR, "Unable to create Gulp channel - endpoint '%s' was not found\n", endpoint_name);
1220 req_data->cause = AST_CAUSE_NO_ROUTE_DESTINATION;
1224 if (!(session = ast_sip_session_create_outgoing(endpoint, args.aor, request_user, req_data->caps))) {
1225 req_data->cause = AST_CAUSE_NO_ROUTE_DESTINATION;
1229 req_data->session = session;
1234 /*! \brief Function called by core to create a new outgoing Gulp session */
1235 static struct ast_channel *gulp_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
1237 struct request_data req_data;
1238 struct ast_sip_session *session;
1240 req_data.caps = cap;
1241 req_data.dest = data;
1243 if (ast_sip_push_task_synchronous(NULL, request, &req_data)) {
1244 *cause = req_data.cause;
1248 session = req_data.session;
1250 if (!(session->channel = gulp_new(session, AST_STATE_DOWN, NULL, NULL, requestor ? ast_channel_linkedid(requestor) : NULL, NULL))) {
1251 /* Session needs to be terminated prematurely */
1255 return session->channel;
1258 /*! \brief Function called by core to send text on Gulp session */
1259 static int gulp_sendtext(struct ast_channel *ast, const char *text)
1264 /*! \brief Convert SIP hangup causes to Asterisk hangup causes */
1265 static int hangup_sip2cause(int cause)
1267 /* Possible values taken from causes.h */
1270 case 401: /* Unauthorized */
1271 return AST_CAUSE_CALL_REJECTED;
1272 case 403: /* Not found */
1273 return AST_CAUSE_CALL_REJECTED;
1274 case 404: /* Not found */
1275 return AST_CAUSE_UNALLOCATED;
1276 case 405: /* Method not allowed */
1277 return AST_CAUSE_INTERWORKING;
1278 case 407: /* Proxy authentication required */
1279 return AST_CAUSE_CALL_REJECTED;
1280 case 408: /* No reaction */
1281 return AST_CAUSE_NO_USER_RESPONSE;
1282 case 409: /* Conflict */
1283 return AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
1284 case 410: /* Gone */
1285 return AST_CAUSE_NUMBER_CHANGED;
1286 case 411: /* Length required */
1287 return AST_CAUSE_INTERWORKING;
1288 case 413: /* Request entity too large */
1289 return AST_CAUSE_INTERWORKING;
1290 case 414: /* Request URI too large */
1291 return AST_CAUSE_INTERWORKING;
1292 case 415: /* Unsupported media type */
1293 return AST_CAUSE_INTERWORKING;
1294 case 420: /* Bad extension */
1295 return AST_CAUSE_NO_ROUTE_DESTINATION;
1296 case 480: /* No answer */
1297 return AST_CAUSE_NO_ANSWER;
1298 case 481: /* No answer */
1299 return AST_CAUSE_INTERWORKING;
1300 case 482: /* Loop detected */
1301 return AST_CAUSE_INTERWORKING;
1302 case 483: /* Too many hops */
1303 return AST_CAUSE_NO_ANSWER;
1304 case 484: /* Address incomplete */
1305 return AST_CAUSE_INVALID_NUMBER_FORMAT;
1306 case 485: /* Ambiguous */
1307 return AST_CAUSE_UNALLOCATED;
1308 case 486: /* Busy everywhere */
1309 return AST_CAUSE_BUSY;
1310 case 487: /* Request terminated */
1311 return AST_CAUSE_INTERWORKING;
1312 case 488: /* No codecs approved */
1313 return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
1314 case 491: /* Request pending */
1315 return AST_CAUSE_INTERWORKING;
1316 case 493: /* Undecipherable */
1317 return AST_CAUSE_INTERWORKING;
1318 case 500: /* Server internal failure */
1319 return AST_CAUSE_FAILURE;
1320 case 501: /* Call rejected */
1321 return AST_CAUSE_FACILITY_REJECTED;
1323 return AST_CAUSE_DESTINATION_OUT_OF_ORDER;
1324 case 503: /* Service unavailable */
1325 return AST_CAUSE_CONGESTION;
1326 case 504: /* Gateway timeout */
1327 return AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE;
1328 case 505: /* SIP version not supported */
1329 return AST_CAUSE_INTERWORKING;
1330 case 600: /* Busy everywhere */
1331 return AST_CAUSE_USER_BUSY;
1332 case 603: /* Decline */
1333 return AST_CAUSE_CALL_REJECTED;
1334 case 604: /* Does not exist anywhere */
1335 return AST_CAUSE_UNALLOCATED;
1336 case 606: /* Not acceptable */
1337 return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
1339 if (cause < 500 && cause >= 400) {
1340 /* 4xx class error that is unknown - someting wrong with our request */
1341 return AST_CAUSE_INTERWORKING;
1342 } else if (cause < 600 && cause >= 500) {
1343 /* 5xx class error - problem in the remote end */
1344 return AST_CAUSE_CONGESTION;
1345 } else if (cause < 700 && cause >= 600) {
1346 /* 6xx - global errors in the 4xx class */
1347 return AST_CAUSE_INTERWORKING;
1349 return AST_CAUSE_NORMAL;
1355 static void gulp_session_begin(struct ast_sip_session *session)
1357 RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
1359 if (session->endpoint->direct_media_glare_mitigation ==
1360 AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_NONE) {
1364 datastore = ast_sip_session_alloc_datastore(&direct_media_mitigation_info,
1365 "direct_media_glare_mitigation");
1371 ast_sip_session_add_datastore(session, datastore);
1374 /*! \brief Function called when the session ends */
1375 static void gulp_session_end(struct ast_sip_session *session)
1377 if (!session->channel) {
1381 if (!ast_channel_hangupcause(session->channel) && session->inv_session) {
1382 int cause = hangup_sip2cause(session->inv_session->cause);
1384 ast_queue_hangup_with_cause(session->channel, cause);
1386 ast_queue_hangup(session->channel);
1390 /*! \brief Function called when a request is received on the session */
1391 static int gulp_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
1393 pjsip_tx_data *packet = NULL;
1394 int res = AST_PBX_FAILED;
1396 if (session->channel) {
1400 if (!(session->channel = gulp_new(session, AST_STATE_RING, session->exten, NULL, NULL, NULL))) {
1401 if (pjsip_inv_end_session(session->inv_session, 503, NULL, &packet) == PJ_SUCCESS) {
1402 ast_sip_session_send_response(session, packet);
1405 ast_log(LOG_ERROR, "Failed to allocate new GULP channel on incoming SIP INVITE\n");
1409 res = ast_pbx_start(session->channel);
1412 case AST_PBX_FAILED:
1413 ast_log(LOG_WARNING, "Failed to start PBX ;(\n");
1414 ast_channel_hangupcause_set(session->channel, AST_CAUSE_SWITCH_CONGESTION);
1415 ast_hangup(session->channel);
1417 case AST_PBX_CALL_LIMIT:
1418 ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
1419 ast_channel_hangupcause_set(session->channel, AST_CAUSE_SWITCH_CONGESTION);
1420 ast_hangup(session->channel);
1422 case AST_PBX_SUCCESS:
1427 ast_debug(3, "Started PBX on new GULP channel %s\n", ast_channel_name(session->channel));
1429 return (res == AST_PBX_SUCCESS) ? 0 : -1;
1432 /*! \brief Function called when a response is received on the session */
1433 static void gulp_incoming_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
1435 struct pjsip_status_line status = rdata->msg_info.msg->line.status;
1437 if (!session->channel) {
1441 switch (status.code) {
1443 ast_queue_control(session->channel, AST_CONTROL_RINGING);
1444 if (ast_channel_state(session->channel) != AST_STATE_UP) {
1445 ast_setstate(session->channel, AST_STATE_RINGING);
1449 ast_queue_control(session->channel, AST_CONTROL_PROGRESS);
1452 ast_queue_control(session->channel, AST_CONTROL_ANSWER);
1459 static int gulp_incoming_ack(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
1461 if (rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD) {
1462 if (session->endpoint->direct_media) {
1463 ast_queue_control(session->channel, AST_CONTROL_SRCCHANGE);
1470 * \brief Load the module
1472 * Module loading including tests for configuration or dependencies.
1473 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
1474 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
1475 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
1476 * configuration file or other non-critical problem return
1477 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
1479 static int load_module(void)
1481 if (!(gulp_tech.capabilities = ast_format_cap_alloc())) {
1482 return AST_MODULE_LOAD_DECLINE;
1485 ast_format_cap_add_all_by_type(gulp_tech.capabilities, AST_FORMAT_TYPE_AUDIO);
1487 ast_rtp_glue_register(&gulp_rtp_glue);
1489 if (ast_channel_register(&gulp_tech)) {
1490 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channel_type);
1494 if (ast_custom_function_register(&gulp_dial_contacts_function)) {
1495 ast_log(LOG_ERROR, "Unable to register GULP_DIAL_CONTACTS dialplan function\n");
1499 if (ast_sip_session_register_supplement(&gulp_supplement)) {
1500 ast_log(LOG_ERROR, "Unable to register Gulp supplement\n");
1504 if (ast_sip_session_register_supplement(&gulp_ack_supplement)) {
1505 ast_log(LOG_ERROR, "Unable to register Gulp ACK supplement\n");
1506 ast_sip_session_unregister_supplement(&gulp_supplement);
1513 ast_custom_function_unregister(&gulp_dial_contacts_function);
1514 ast_channel_unregister(&gulp_tech);
1515 ast_rtp_glue_unregister(&gulp_rtp_glue);
1517 return AST_MODULE_LOAD_FAILURE;
1520 /*! \brief Reload module */
1521 static int reload(void)
1526 /*! \brief Unload the Gulp channel from Asterisk */
1527 static int unload_module(void)
1529 ast_sip_session_unregister_supplement(&gulp_supplement);
1530 ast_custom_function_unregister(&gulp_dial_contacts_function);
1531 ast_channel_unregister(&gulp_tech);
1532 ast_rtp_glue_unregister(&gulp_rtp_glue);
1537 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Gulp SIP Channel Driver",
1538 .load = load_module,
1539 .unload = unload_module,
1541 .load_pri = AST_MODPRI_CHANNEL_DRIVER,