func_periodic_hook.c File Reference

Periodic dialplan hooks. More...

#include "asterisk.h"
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/audiohook.h"
#include "asterisk/beep.h"

Include dependency graph for func_periodic_hook.c:

Go to the source code of this file.

Data Structures

struct  hook_state
struct  hook_thread_arg

Defines

#define AST_API_MODULE

Functions

static void __reg_module (void)
static void __unreg_module (void)
int AST_OPTIONAL_API_NAME() ast_beep_start (struct ast_channel *chan, unsigned int interval, char *beep_id, size_t len)
int AST_OPTIONAL_API_NAME() ast_beep_stop (struct ast_channel *chan, const char *beep_id)
static int do_hook (struct ast_channel *chan, struct hook_state *state)
static int hook_callback (struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
static void hook_datastore_destroy_callback (void *data)
static void * hook_launch_thread (void *data)
static int hook_off (struct ast_channel *chan, const char *hook_id)
static int hook_on (struct ast_channel *chan, const char *data, unsigned int hook_id)
static int hook_re_enable (struct ast_channel *chan, const char *uid)
static int hook_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static struct hook_statehook_state_alloc (const char *context, const char *exten, unsigned int interval, unsigned int hook_id)
static struct hook_thread_arghook_thread_arg_alloc (struct ast_channel *chan, struct hook_state *state)
static void hook_thread_arg_destroy (struct hook_thread_arg *arg)
static int hook_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
static int init_hook (struct ast_channel *chan, const char *context, const char *exten, unsigned int interval, unsigned int hook_id)
static int load_module (void)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS , .description = "Periodic dialplan hooks." , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, }
static struct ast_module_infoast_module_info = &__mod_info
static const char beep_exten [] = "beep"
static const char context_name [] = "__func_periodic_hook_context__"
static const char exten_name [] = "hook"
static const char full_exten_name [] = "hook@__func_periodic_hook_context__"
static struct ast_contextfunc_periodic_hook_context
static unsigned int global_hook_id
 Last used hook ID.
static struct ast_datastore_info hook_datastore
static struct ast_custom_function hook_function


Detailed Description

Periodic dialplan hooks.

Author:
Russell Bryant <russell@russellbryant.net>

Definition in file func_periodic_hook.c.


Define Documentation

#define AST_API_MODULE

Definition at line 45 of file func_periodic_hook.c.


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 527 of file func_periodic_hook.c.

static void __unreg_module ( void   )  [static]

Definition at line 527 of file func_periodic_hook.c.

int AST_OPTIONAL_API_NAME() ast_beep_start ( struct ast_channel chan,
unsigned int  interval,
char *  beep_id,
size_t  len 
)

Definition at line 502 of file func_periodic_hook.c.

References args, ast_log, AST_MAX_CONTEXT, AST_MAX_EXTENSION, hook_read(), len(), LOG_WARNING, and NULL.

Referenced by mixmonitor_exec(), and start_monitor_exec().

00504 {
00505    char args[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 32];
00506 
00507    snprintf(args, sizeof(args), "%s,%s,%u",
00508          context_name, beep_exten, interval);
00509 
00510    if (hook_read(chan, NULL, args, beep_id, len)) {
00511       ast_log(LOG_WARNING, "Failed to enable periodic beep.\n");
00512       return -1;
00513    }
00514 
00515    return 0;
00516 }

int AST_OPTIONAL_API_NAME() ast_beep_stop ( struct ast_channel chan,
const char *  beep_id 
)

Definition at line 518 of file func_periodic_hook.c.

References hook_write(), and NULL.

Referenced by ast_monitor_stop(), and stop_mixmonitor_full().

00519 {
00520    return hook_write(chan, NULL, (char *) beep_id, "off");
00521 }

static int do_hook ( struct ast_channel chan,
struct hook_state state 
) [static]

Definition at line 229 of file func_periodic_hook.c.

References ast_pthread_create_detached_background, hook_launch_thread(), hook_thread_arg_alloc(), hook_thread_arg_destroy(), and NULL.

Referenced by hook_callback().

00230 {
00231    pthread_t t;
00232    struct hook_thread_arg *arg;
00233    int res;
00234 
00235    if (!(arg = hook_thread_arg_alloc(chan, state))) {
00236       return -1;
00237    }
00238 
00239    /*
00240     * We don't want to block normal frame processing *at all* while we kick
00241     * this off, so do it in a new thread.
00242     */
00243    res = ast_pthread_create_detached_background(&t, NULL, hook_launch_thread, arg);
00244    if (res != 0) {
00245       hook_thread_arg_destroy(arg);
00246    }
00247 
00248    return res;
00249 }

static int hook_callback ( struct ast_audiohook audiohook,
struct ast_channel chan,
struct ast_frame frame,
enum ast_audiohook_direction  direction 
) [static]

Definition at line 251 of file func_periodic_hook.c.

References AST_AUDIOHOOK_STATUS_DONE, ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_log, ast_strdupa, ast_tvdiff_ms(), ast_tvnow(), hook_state::disabled, do_hook(), hook_state::interval, hook_state::last_hook, LOG_WARNING, name, and ast_audiohook::status.

Referenced by hook_state_alloc().

00253 {
00254    struct hook_state *state = (struct hook_state *) audiohook; /* trust me. */
00255    struct timeval now;
00256    int res = 0;
00257 
00258    if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE || state->disabled) {
00259       return 0;
00260    }
00261 
00262    now = ast_tvnow();
00263    if (ast_tvdiff_ms(now, state->last_hook) > state->interval * 1000) {
00264       if ((res = do_hook(chan, state))) {
00265          const char *name;
00266          ast_channel_lock(chan);
00267          name = ast_strdupa(ast_channel_name(chan));
00268          ast_channel_unlock(chan);
00269          ast_log(LOG_WARNING, "Failed to run hook on '%s'\n", name);
00270       }
00271       state->last_hook = now;
00272    }
00273 
00274    return res;
00275 }

static void hook_datastore_destroy_callback ( void *  data  )  [static]

Definition at line 130 of file func_periodic_hook.c.

References ast_audiohook_destroy(), ast_audiohook_detach(), ast_audiohook_lock, ast_audiohook_unlock, ast_free, ast_module_unref, hook_state::audiohook, hook_state::context, and hook_state::exten.

00131 {
00132    struct hook_state *state = data;
00133 
00134    ast_audiohook_lock(&state->audiohook);
00135    ast_audiohook_detach(&state->audiohook);
00136    ast_audiohook_unlock(&state->audiohook);
00137    ast_audiohook_destroy(&state->audiohook);
00138 
00139    ast_free(state->context);
00140    ast_free(state->exten);
00141    ast_free(state);
00142 
00143    ast_module_unref(ast_module_info->self);
00144 }

static void* hook_launch_thread ( void *  data  )  [static]

Definition at line 172 of file func_periodic_hook.c.

References ast_pbx_outgoing_exten(), hook_thread_arg::chan_name, hook_thread_arg::context, hook_thread_arg::exten, hook_thread_arg::hook_id, hook_thread_arg_destroy(), ast_variable::name, and NULL.

Referenced by do_hook().

00173 {
00174    struct hook_thread_arg *arg = data;
00175    struct ast_variable hook_id = {
00176       .name = "HOOK_ID",
00177       .value = arg->hook_id,
00178    };
00179    struct ast_variable chan_name_var = {
00180       .name = "HOOK_CHANNEL",
00181       .value = arg->chan_name,
00182       .next = &hook_id,
00183    };
00184 
00185    ast_pbx_outgoing_exten("Local", NULL, full_exten_name, 60,
00186          arg->context, arg->exten, 1, NULL, 0, NULL, NULL, &chan_name_var,
00187          NULL, NULL, 1, NULL);
00188 
00189    hook_thread_arg_destroy(arg);
00190 
00191    return NULL;
00192 }

static int hook_off ( struct ast_channel chan,
const char *  hook_id 
) [static]

Definition at line 354 of file func_periodic_hook.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_log, ast_strlen_zero, ast_datastore::data, hook_state::disabled, and LOG_WARNING.

Referenced by hook_write().

00355 {
00356    struct ast_datastore *datastore;
00357    struct hook_state *state;
00358 
00359    if (ast_strlen_zero(hook_id)) {
00360       return -1;
00361    }
00362 
00363    ast_channel_lock(chan);
00364 
00365    if (!(datastore = ast_channel_datastore_find(chan, &hook_datastore, hook_id))) {
00366       ast_log(LOG_WARNING, "Hook with ID '%s' not found on channel '%s'\n", hook_id,
00367             ast_channel_name(chan));
00368       ast_channel_unlock(chan);
00369       return -1;
00370    }
00371 
00372    state = datastore->data;
00373    state->disabled = 1;
00374 
00375    ast_channel_unlock(chan);
00376 
00377    return 0;
00378 }

static int hook_on ( struct ast_channel chan,
const char *  data,
unsigned int  hook_id 
) [static]

Definition at line 325 of file func_periodic_hook.c.

References args, AST_APP_ARG, ast_channel_name(), ast_debug, AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero, context, exten, init_hook(), LOG_WARNING, parse(), and S_OR.

Referenced by hook_read().

00326 {
00327    char *parse = ast_strdupa(S_OR(data, ""));
00328    AST_DECLARE_APP_ARGS(args,
00329       AST_APP_ARG(context);
00330       AST_APP_ARG(exten);
00331       AST_APP_ARG(interval);
00332    );
00333    unsigned int interval;
00334 
00335    AST_STANDARD_APP_ARGS(args, parse);
00336 
00337    if (ast_strlen_zero(args.interval) ||
00338          sscanf(args.interval, "%30u", &interval) != 1 || interval == 0) {
00339       ast_log(LOG_WARNING, "Invalid hook interval: '%s'\n", S_OR(args.interval, ""));
00340       return -1;
00341    }
00342 
00343    if (ast_strlen_zero(args.context) || ast_strlen_zero(args.exten)) {
00344       ast_log(LOG_WARNING, "A context and extension are required for PERIODIC_HOOK().\n");
00345       return -1;
00346    }
00347 
00348    ast_debug(1, "hook to %s@%s enabled on %s with interval of %u seconds\n",
00349          args.exten, args.context, ast_channel_name(chan), interval);
00350 
00351    return init_hook(chan, args.context, args.exten, interval, hook_id);
00352 }

static int hook_re_enable ( struct ast_channel chan,
const char *  uid 
) [static]

Definition at line 396 of file func_periodic_hook.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_log, ast_strlen_zero, ast_datastore::data, hook_state::disabled, and LOG_WARNING.

Referenced by hook_write().

00397 {
00398    struct ast_datastore *datastore;
00399    struct hook_state *state;
00400 
00401    if (ast_strlen_zero(uid)) {
00402       return -1;
00403    }
00404 
00405    ast_channel_lock(chan);
00406 
00407    if (!(datastore = ast_channel_datastore_find(chan, &hook_datastore, uid))) {
00408       ast_log(LOG_WARNING, "Hook with ID '%s' not found on '%s'\n",
00409             uid, ast_channel_name(chan));
00410       ast_channel_unlock(chan);
00411       return -1;
00412    }
00413 
00414    state = datastore->data;
00415    state->disabled = 0;
00416 
00417    ast_channel_unlock(chan);
00418 
00419    return 0;
00420 }

static int hook_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Definition at line 380 of file func_periodic_hook.c.

References ast_atomic_fetchadd_int(), hook_state::hook_id, and hook_on().

Referenced by ast_beep_start().

00382 {
00383    unsigned int hook_id;
00384 
00385    if (!chan) {
00386       return -1;
00387    }
00388 
00389    hook_id = (unsigned int) ast_atomic_fetchadd_int((int *) &global_hook_id, 1);
00390 
00391    snprintf(buf, len, "%u", hook_id);
00392 
00393    return hook_on(chan, data, hook_id);
00394 }

static struct hook_state* hook_state_alloc ( const char *  context,
const char *  exten,
unsigned int  interval,
unsigned int  hook_id 
) [static, read]

Definition at line 277 of file func_periodic_hook.c.

References ast_audiohook_init(), AST_AUDIOHOOK_MANIPULATE_ALL_RATES, AST_AUDIOHOOK_TYPE_MANIPULATE, ast_calloc, ast_strdup, hook_state::audiohook, hook_state::context, hook_state::exten, hook_callback(), hook_state::hook_id, hook_state::interval, ast_audiohook::manipulate_callback, and NULL.

Referenced by init_hook().

00279 {
00280    struct hook_state *state;
00281 
00282    if (!(state = ast_calloc(1, sizeof(*state)))) {
00283       return NULL;
00284    }
00285 
00286    state->context = ast_strdup(context);
00287    state->exten = ast_strdup(exten);
00288    state->interval = interval;
00289    state->hook_id = hook_id;
00290 
00291    ast_audiohook_init(&state->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE,
00292          AST_MODULE, AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
00293    state->audiohook.manipulate_callback = hook_callback;
00294 
00295    return state;
00296 }

static struct hook_thread_arg* hook_thread_arg_alloc ( struct ast_channel chan,
struct hook_state state 
) [static, read]

Definition at line 194 of file func_periodic_hook.c.

References ast_asprintf, ast_calloc, ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_strdup, hook_thread_arg::chan_name, hook_state::context, hook_thread_arg::context, hook_state::exten, hook_thread_arg::exten, hook_state::hook_id, hook_thread_arg::hook_id, hook_thread_arg_destroy(), and NULL.

Referenced by do_hook().

00196 {
00197    struct hook_thread_arg *arg;
00198 
00199    if (!(arg = ast_calloc(1, sizeof(*arg)))) {
00200       return NULL;
00201    }
00202 
00203    ast_channel_lock(chan);
00204    arg->chan_name = ast_strdup(ast_channel_name(chan));
00205    ast_channel_unlock(chan);
00206    if (!arg->chan_name) {
00207       hook_thread_arg_destroy(arg);
00208       return NULL;
00209    }
00210 
00211    if (ast_asprintf(&arg->hook_id, "%u", state->hook_id) == -1) {
00212       hook_thread_arg_destroy(arg);
00213       return NULL;
00214    }
00215 
00216    if (!(arg->context = ast_strdup(state->context))) {
00217       hook_thread_arg_destroy(arg);
00218       return NULL;
00219    }
00220 
00221    if (!(arg->exten = ast_strdup(state->exten))) {
00222       hook_thread_arg_destroy(arg);
00223       return NULL;
00224    }
00225 
00226    return arg;
00227 }

static void hook_thread_arg_destroy ( struct hook_thread_arg arg  )  [static]

Definition at line 163 of file func_periodic_hook.c.

References ast_free, hook_thread_arg::chan_name, hook_thread_arg::context, hook_thread_arg::exten, and hook_thread_arg::hook_id.

Referenced by do_hook(), hook_launch_thread(), and hook_thread_arg_alloc().

00164 {
00165    ast_free(arg->hook_id);
00166    ast_free(arg->chan_name);
00167    ast_free(arg->context);
00168    ast_free(arg->exten);
00169    ast_free(arg);
00170 }

static int hook_write ( struct ast_channel chan,
const char *  cmd,
char *  data,
const char *  value 
) [static]

Definition at line 422 of file func_periodic_hook.c.

References ast_false(), ast_log, ast_true(), hook_off(), hook_re_enable(), and LOG_WARNING.

Referenced by ast_beep_stop().

00424 {
00425    int res;
00426 
00427    if (!chan) {
00428       return -1;
00429    }
00430 
00431    if (ast_false(value)) {
00432       res = hook_off(chan, data);
00433    } else if (ast_true(value)) {
00434       res = hook_re_enable(chan, data);
00435    } else {
00436       ast_log(LOG_WARNING, "Invalid value for PERIODIC_HOOK function: '%s'\n", value);
00437       res = -1;
00438    }
00439 
00440    return res;
00441 }

static int init_hook ( struct ast_channel chan,
const char *  context,
const char *  exten,
unsigned int  interval,
unsigned int  hook_id 
) [static]

Definition at line 298 of file func_periodic_hook.c.

References ast_audiohook_attach(), ast_channel_datastore_add(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_datastore_free(), ast_module_ref, hook_state::audiohook, ast_datastore::data, hook_state_alloc(), and ast_datastore::uid.

Referenced by hook_on().

00300 {
00301    struct hook_state *state;
00302    struct ast_datastore *datastore;
00303    char uid[32];
00304 
00305    snprintf(uid, sizeof(uid), "%u", hook_id);
00306 
00307    if (!(datastore = ast_datastore_alloc(&hook_datastore, uid))) {
00308       return -1;
00309    }
00310    ast_module_ref(ast_module_info->self);
00311    if (!(state = hook_state_alloc(context, exten, interval, hook_id))) {
00312       ast_datastore_free(datastore);
00313       return -1;
00314    }
00315    datastore->data = state;
00316 
00317    ast_channel_lock(chan);
00318    ast_channel_datastore_add(chan, datastore);
00319    ast_audiohook_attach(chan, &state->audiohook);
00320    ast_channel_unlock(chan);
00321 
00322    return 0;
00323 }

static int load_module ( void   )  [static]

Definition at line 460 of file func_periodic_hook.c.

References ast_add_extension(), AST_CFE_BOTH, ast_context_find_or_create(), ast_custom_function_register_escalating, ast_log, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, LOG_ERROR, and NULL.

00461 {
00462    int res;
00463 
00464    func_periodic_hook_context = ast_context_find_or_create(NULL, NULL,
00465          context_name, AST_MODULE);
00466    if (!func_periodic_hook_context) {
00467       ast_log(LOG_ERROR, "Failed to create %s dialplan context.\n", context_name);
00468       return AST_MODULE_LOAD_DECLINE;
00469    }
00470 
00471    /*
00472     * Based on a handy recipe from the Asterisk Cookbook.
00473     */
00474    ast_add_extension(context_name, 1, exten_name, 1, "", "",
00475          "Set", "EncodedChannel=${CUT(HOOK_CHANNEL,-,1-2)}",
00476          NULL, AST_MODULE);
00477    ast_add_extension(context_name, 1, exten_name, 2, "", "",
00478          "Set", "GROUP_NAME=${EncodedChannel}${HOOK_ID}",
00479          NULL, AST_MODULE);
00480    ast_add_extension(context_name, 1, exten_name, 3, "", "",
00481          "Set", "GROUP(periodic-hook)=${GROUP_NAME}",
00482          NULL, AST_MODULE);
00483    ast_add_extension(context_name, 1, exten_name, 4, "", "", "ExecIf",
00484          "$[${GROUP_COUNT(${GROUP_NAME}@periodic-hook)} > 1]?Hangup()",
00485          NULL, AST_MODULE);
00486    ast_add_extension(context_name, 1, exten_name, 5, "", "",
00487          "Set", "ChannelToSpy=${URIDECODE(${EncodedChannel})}",
00488          NULL, AST_MODULE);
00489    ast_add_extension(context_name, 1, exten_name, 6, "", "",
00490          "ChanSpy", "${ChannelToSpy},qEB", NULL, AST_MODULE);
00491 
00492    res = ast_add_extension(context_name, 1, beep_exten, 1, "", "",
00493          "Answer", "", NULL, AST_MODULE);
00494    res |= ast_add_extension(context_name, 1, beep_exten, 2, "", "",
00495          "Playback", "beep", NULL, AST_MODULE);
00496 
00497    res = ast_custom_function_register_escalating(&hook_function, AST_CFE_BOTH);
00498 
00499    return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
00500 }

static int unload_module ( void   )  [static]

Definition at line 451 of file func_periodic_hook.c.

References ast_context_destroy(), and ast_custom_function_unregister().

00452 {
00453    if (func_periodic_hook_context) {
00454       ast_context_destroy(func_periodic_hook_context, AST_MODULE);
00455    }
00456 
00457    return ast_custom_function_unregister(&hook_function);
00458 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS , .description = "Periodic dialplan hooks." , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, } [static]

Definition at line 527 of file func_periodic_hook.c.

Definition at line 527 of file func_periodic_hook.c.

const char beep_exten[] = "beep" [static]

Definition at line 98 of file func_periodic_hook.c.

const char context_name[] = "__func_periodic_hook_context__" [static]

const char exten_name[] = "hook" [static]

Definition at line 95 of file func_periodic_hook.c.

Referenced by destroy_hint(), device_state_cb(), hint_hash(), and presence_state_cb().

const char full_exten_name[] = "hook@__func_periodic_hook_context__" [static]

Definition at line 96 of file func_periodic_hook.c.

Definition at line 449 of file func_periodic_hook.c.

unsigned int global_hook_id [static]

Last used hook ID.

This is incremented each time a hook is created to give each hook a unique ID.

Definition at line 106 of file func_periodic_hook.c.

Initial value:

 {
   .type = AST_MODULE,
   .destroy = hook_datastore_destroy_callback,
}

Definition at line 146 of file func_periodic_hook.c.

Initial value:

 {
   .name = "PERIODIC_HOOK",
   .read = hook_read,
   .write = hook_write,
}

Definition at line 443 of file func_periodic_hook.c.


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