Asterisk - The Open Source Telephony Project  18.5.0
Asterisk FrameHook API

How FrameHooks Work

FrameHooks work by intercepting all frames being written and read off a channel and allowing those frames to be viewed and manipulated within a call back function. Frame interception occurs before any processing is done on the frame, which means this hook can be used to transparently manipulate a frame before it is read from the channel or written to the tech_pvt. This API can be thought of as a layer between the channel API and the Asterisk core when going in the READ direction, and as a layer between the Channel API and the tech_pvt when going in the WRITE direction.

How to Use an FrameHook

Attaching and detaching an FrameHook to a channel is very simple. There are only two functions involved, ast_framehook_attach() which will return an id representing the new FrameHook on the channel, and ast_framehook_detach() which signals the FrameHook for detachment and destruction. Below is detailed information each of these functions and their usage.

struct ast_framehook_interface interface = {
.event_cb = hook_event_cb,
.destroy_cb = hook_destroy_cb,
.data = data, // where the data ptr points to any custom data used later by the hook cb.
};
int id = ast_framehook_attach(channel, &interface);

The ast_framehook_attach() function creates and attaches a new FrameHook onto a channel. Once attached to the channel, the FrameHook will call the event_callback function each time a frame is written or read on the channel. A custom data pointer can be provided to this function to store on the FrameHook as well. This pointer can be used to keep up with any statefull information associated with the FrameHook and is provided during the event_callback function. The destroy_callback function is optional. This function exists so any custom data stored on the FrameHook can be destroyed before the Framehook if destroyed.

The ast_framehook_detach() function signals the FrameHook represented by an id to be detached and destroyed on a channel. Since it is possible this function may be called during the FrameHook's event callback, it is impossible to synchronously detach the FrameHook from the channel during this function call. It is guaranteed that the next event proceeding the ast_framehook_detach() will be of type AST_FRAMEHOOK_EVENT_DETACH, and that after that event occurs no other event will ever be issued for that FrameHook. Once the FrameHook is destroyed, the destroy callback function will be called if it was provided. Note that if this function is never called, the FrameHook will be detached on channel destruction.

FrameHook Example Code

The example code below attaches an FrameHook on a channel, and then detachs it when the first ast_frame is read or written to the event callback function. The Framehook's id is stored on the FrameHook's data pointer so it can be detached within the callback.

static void destroy_cb(void *data) {
ast_free(data);
}
static struct ast_frame *event_cb(struct ast_channel *chan,
struct ast_frame *frame,
void *data) {
int *id = data;
if (!frame) {
return frame;
}
if (event == AST_FRAMEHOOK_EVENT_WRITE) {
ast_log(LOG_NOTICE, "YAY we received a frame in the write direction, Type: %d\n", frame->frametype)
ast_framehook_detach(chan, id); // the channel is guaranteed to be locked during this function call.
} else if (event == AST_FRAMEHOOK_EVENT_READ) {
ast_log(LOG_NOTICE, "YAY we received a frame in the read direction: Type: %d\n", frame->frametype);
ast_framehook_detach(chan, id); // the channel is guaranteed to be locked during this function call.
}
return frame;
{
int some_function()
{
struct ast_framehook_interface interface = {
.event_cb = hook_event_cb,
.destroy_cb = hook_destroy_cb,
};
int *id = ast_calloc(1, sizeof(int));
if (!id) {
return -1;
}
interface.data = id; // This data will be returned to us in the callbacks.
*id = ast_framehook_attach(chan, &interface);
if (*id < 0) {
// framehook attach failed, free data
ast_free(id);
return -1;
}
return 0;
}