Asterisk - The Open Source Telephony Project GIT-master-f36a736
func_holdintercept.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2015, Digium, Inc.
5 *
6 * Matt Jordan <mjordan@digium.com>
7 *
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.
13 *
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.
17 */
18
19/*! \file
20 *
21 * \brief Function that intercepts HOLD frames from channels and raises events
22 *
23 * \author Matt Jordan <mjordan@digium.com>
24 *
25 * \ingroup functions
26 */
27
28/*** MODULEINFO
29 <support_level>core</support_level>
30 ***/
31
32#include "asterisk.h"
33
34#include "asterisk/module.h"
35#include "asterisk/channel.h"
36#include "asterisk/pbx.h"
37#include "asterisk/app.h"
38#include "asterisk/frame.h"
39#include "asterisk/stasis.h"
41
42/*** DOCUMENTATION
43 <function name="HOLD_INTERCEPT" language="en_US">
44 <synopsis>
45 Intercepts hold frames on a channel and raises an event instead of passing the frame on
46 </synopsis>
47 <syntax>
48 <parameter name="action" required="true">
49 <optionlist>
50 <option name="remove">
51 <para>W/O. Removes the hold interception function.</para>
52 </option>
53 <option name="set">
54 <para>W/O. Enable hold interception on the channel. When
55 enabled, the channel will intercept any hold action that
56 is signalled from the device, and instead simply raise an
57 event (AMI/ARI) indicating that the channel wanted to put other
58 parties on hold.</para>
59 </option>
60 </optionlist>
61 </parameter>
62 </syntax>
63 </function>
64***/
65
66/*! \brief Private data structure used with the function's datastore */
69};
70
71/*! \brief The channel datastore the function uses to store state */
73 .type = "hold_intercept",
74};
75
76/*! \internal \brief Disable hold interception on the channel */
77static int remove_hold_intercept(struct ast_channel *chan)
78{
79 struct ast_datastore *datastore = NULL;
80 struct hold_intercept_data *data;
81 SCOPED_CHANNELLOCK(chan_lock, chan);
82
84 if (!datastore) {
85 ast_log(AST_LOG_WARNING, "Cannot remove HOLD_INTERCEPT from %s: HOLD_INTERCEPT not currently enabled\n",
86 ast_channel_name(chan));
87 return -1;
88 }
89 data = datastore->data;
90
91 if (ast_framehook_detach(chan, data->framehook_id)) {
92 ast_log(AST_LOG_WARNING, "Failed to remove HOLD_INTERCEPT framehook from channel %s\n",
93 ast_channel_name(chan));
94 return -1;
95 }
96
97 if (ast_channel_datastore_remove(chan, datastore)) {
98 ast_log(AST_LOG_WARNING, "Failed to remove HOLD_INTERCEPT datastore from channel %s\n",
99 ast_channel_name(chan));
100 return -1;
101 }
102 ast_datastore_free(datastore);
103
104 return 0;
105}
106
107/*! \brief Frame hook that is called to intercept hold/unhold */
109 struct ast_frame *f, enum ast_framehook_event event, void *data)
110{
111 int frame_type;
112
113 if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) {
114 return f;
115 }
116
117 if (f->frametype != AST_FRAME_CONTROL) {
118 return f;
119 }
120
123 return f;
124 }
125
126 /* Munch munch */
127 ast_frfree(f);
128 f = &ast_null_frame;
129
132 NULL);
133
134 return f;
135}
136
137/*! \brief Callback function which informs upstream if we are consuming a frame of a specific type */
139{
140 return (type == AST_FRAME_CONTROL ? 1 : 0);
141}
142
143/*! \internal \brief Enable hold interception on the channel */
144static int set_hold_intercept(struct ast_channel *chan)
145{
146 struct ast_datastore *datastore;
147 struct hold_intercept_data *data;
148 static struct ast_framehook_interface hold_framehook_interface = {
150 .event_cb = hold_intercept_framehook,
152 .disable_inheritance = 1,
153 };
154 SCOPED_CHANNELLOCK(chan_lock, chan);
155
157 if (datastore) {
158 ast_log(AST_LOG_WARNING, "HOLD_INTERCEPT already set on '%s'\n",
159 ast_channel_name(chan));
160 return 0;
161 }
162
164 if (!datastore) {
165 return -1;
166 }
167
168 data = ast_calloc(1, sizeof(*data));
169 if (!data) {
170 ast_datastore_free(datastore);
171 return -1;
172 }
173
174 data->framehook_id = ast_framehook_attach(chan, &hold_framehook_interface);
175 if (data->framehook_id < 0) {
176 ast_log(AST_LOG_WARNING, "Failed to attach HOLD_INTERCEPT framehook to '%s'\n",
177 ast_channel_name(chan));
178 ast_datastore_free(datastore);
179 ast_free(data);
180 return -1;
181 }
182 datastore->data = data;
183
184 ast_channel_datastore_add(chan, datastore);
185
186 return 0;
187}
188
189/*! \internal \brief HOLD_INTERCEPT write function callback */
190static int hold_intercept_fn_write(struct ast_channel *chan, const char *function,
191 char *data, const char *value)
192{
193 int res;
194
195 if (!chan) {
196 return -1;
197 }
198
199 if (ast_strlen_zero(data)) {
200 ast_log(AST_LOG_WARNING, "HOLD_INTERCEPT requires an argument\n");
201 return -1;
202 }
203
204 if (!strcasecmp(data, "set")) {
205 res = set_hold_intercept(chan);
206 } else if (!strcasecmp(data, "remove")) {
207 res = remove_hold_intercept(chan);
208 } else {
209 ast_log(AST_LOG_WARNING, "HOLD_INTERCEPT: unknown option %s\n", data);
210 res = -1;
211 }
212
213 return res;
214}
215
216/*! \brief Definition of the HOLD_INTERCEPT function */
218 .name = "HOLD_INTERCEPT",
220};
221
222/*! \internal \brief Unload the module */
223static int unload_module(void)
224{
226}
227
228/*! \internal \brief Load the module */
229static int load_module(void)
230{
232}
233
234AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Hold interception dialplan function");
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
static const char type[]
Definition: chan_ooh323.c:109
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2404
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2413
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2418
frame_type
Definition: codec_builtin.c:44
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
int ast_framehook_attach(struct ast_channel *chan, struct ast_framehook_interface *i)
Attach an framehook onto a channel for frame interception.
Definition: framehook.c:132
ast_framehook_event
These are the types of events that the framehook's event callback can receive.
Definition: framehook.h:151
@ AST_FRAMEHOOK_EVENT_WRITE
Definition: framehook.h:153
int ast_framehook_detach(struct ast_channel *chan, int framehook_id)
Detach an framehook from a channel.
Definition: framehook.c:177
#define AST_FRAMEHOOK_INTERFACE_VERSION
Definition: framehook.h:227
static struct ast_custom_function hold_intercept_function
Definition of the HOLD_INTERCEPT function.
static int hold_intercept_framehook_consume(void *data, enum ast_frame_type type)
Callback function which informs upstream if we are consuming a frame of a specific type.
static int hold_intercept_fn_write(struct ast_channel *chan, const char *function, char *data, const char *value)
static int remove_hold_intercept(struct ast_channel *chan)
static const struct ast_datastore_info hold_intercept_datastore
The channel datastore the function uses to store state.
static int load_module(void)
static int unload_module(void)
static int set_hold_intercept(struct ast_channel *chan)
static struct ast_frame * hold_intercept_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data)
Frame hook that is called to intercept hold/unhold.
struct stasis_message_type * ast_channel_hold_type(void)
Message type for when a channel is placed on hold.
void ast_channel_publish_cached_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Publish a channel blob message using the latest snapshot from the cache.
struct stasis_message_type * ast_channel_unhold_type(void)
Message type for when a channel is removed from hold.
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
Asterisk internal frame definitions.
#define ast_frfree(fr)
ast_frame_type
Frame types.
@ AST_FRAME_CONTROL
@ AST_CONTROL_UNHOLD
@ AST_CONTROL_HOLD
struct ast_frame ast_null_frame
Definition: main/frame.c:79
#define AST_LOG_WARNING
#define SCOPED_CHANNELLOCK(varname, chan)
scoped lock specialization for channels.
Definition: lock.h:619
Asterisk module definitions.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:581
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
Core PBX routines and definitions.
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
#define NULL
Definition: resample.c:96
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Main Channel structure associated with a channel.
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
const char * name
Definition: pbx.h:119
Structure for a data store type.
Definition: datastore.h:31
const char * type
Definition: datastore.h:32
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
union ast_frame::@226 data
enum ast_frame_type frametype
Definition: astman.c:222
Private data structure used with the function's datastore.
int value
Definition: syslog.c:37