static int frame_trace_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value) { struct frame_trace_data *framedata; struct ast_datastore *datastore = NULL; struct ast_framehook_interface interface = { .version = AST_FRAMEHOOK_INTERFACE_VERSION, .event_cb = hook_event_cb, .destroy_cb = hook_destroy_cb, }; int i = 0; if (!(framedata = ast_calloc(1, sizeof(*framedata)))) { return 0; } interface.data = framedata; if (!strcasecmp(data, "black")) { framedata->list_type = 1; } for (i = 0; i < ARRAY_LEN(frametype2str); i++) { if (strcasestr(value, frametype2str[i].str)) { framedata->values[i] = 1; } } ast_channel_lock(chan); i = ast_framehook_attach(chan, &interface); if (i >= 0) { int *id; if ((datastore = ast_channel_datastore_find(chan, &frame_trace_datastore, NULL))) { id = datastore->data; ast_framehook_detach(chan, *id); ast_channel_datastore_remove(chan, datastore); } if (!(datastore = ast_datastore_alloc(&frame_trace_datastore, NULL))) { ast_framehook_detach(chan, i); ast_channel_unlock(chan); return 0; } if (!(id = ast_calloc(1, sizeof(int)))) { ast_datastore_free(datastore); ast_framehook_detach(chan, i); ast_channel_unlock(chan); return 0; } *id = i; /* Store off the id. The channel is still locked so it is safe to access this ptr. */ datastore->data = id; ast_channel_datastore_add(chan, datastore); } ast_channel_unlock(chan); return 0; }
static void t38_masq(void *data, int framehook_id, struct ast_channel *old_chan, struct ast_channel *new_chan) { if (ast_channel_tech(old_chan) == ast_channel_tech(new_chan)) { return; } /* This framehook is only applicable to PJSIP channels */ ast_framehook_detach(new_chan, framehook_id); }
/*! \brief Function called to attach T.38 framehook to channel when appropriate */ static void t38_attach_framehook(struct ast_sip_session *session) { int framehook_id; struct ast_datastore *datastore = NULL; static struct ast_framehook_interface hook = { .version = AST_FRAMEHOOK_INTERFACE_VERSION, .event_cb = t38_framehook, .consume_cb = t38_consume, .chan_fixup_cb = t38_masq, .chan_breakdown_cb = t38_masq, }; /* If the channel's already gone, bail */ if (!session->channel) { return; } /* Only attach the framehook if t38 is enabled for the endpoint */ if (!session->endpoint->media.t38.enabled) { return; } /* Skip attaching the framehook if the T.38 datastore already exists for the channel */ ast_channel_lock(session->channel); if ((datastore = ast_channel_datastore_find(session->channel, &t38_framehook_datastore, NULL))) { ast_channel_unlock(session->channel); return; } ast_channel_unlock(session->channel); framehook_id = ast_framehook_attach(session->channel, &hook); if (framehook_id < 0) { ast_log(LOG_WARNING, "Could not attach T.38 Frame hook to channel, T.38 will be unavailable on '%s'\n", ast_channel_name(session->channel)); return; } ast_channel_lock(session->channel); datastore = ast_datastore_alloc(&t38_framehook_datastore, NULL); if (!datastore) { ast_log(LOG_ERROR, "Could not attach T.38 Frame hook to channel, T.38 will be unavailable on '%s'\n", ast_channel_name(session->channel)); ast_framehook_detach(session->channel, framehook_id); ast_channel_unlock(session->channel); return; } ast_channel_datastore_add(session->channel, datastore); ast_channel_unlock(session->channel); }
/*! \brief Helper function which adds frame hook to bridge channel */ static int native_rtp_bridge_framehook_attach(struct ast_bridge_channel *bridge_channel) { struct native_rtp_bridge_data *data = ao2_alloc(sizeof(*data), NULL); static struct ast_framehook_interface hook = { .version = AST_FRAMEHOOK_INTERFACE_VERSION, .event_cb = native_rtp_framehook, .destroy_cb = __ao2_cleanup, .consume_cb = native_rtp_framehook_consume, .disable_inheritance = 1, }; if (!data) { return -1; } ast_channel_lock(bridge_channel->chan); hook.data = ao2_bump(data); data->id = ast_framehook_attach(bridge_channel->chan, &hook); ast_channel_unlock(bridge_channel->chan); if (data->id < 0) { /* We need to drop both the reference we hold, and the one the framehook would hold */ ao2_ref(data, -2); return -1; } bridge_channel->tech_pvt = data; return 0; } /*! \brief Helper function which removes frame hook from bridge channel */ static void native_rtp_bridge_framehook_detach(struct ast_bridge_channel *bridge_channel) { RAII_VAR(struct native_rtp_bridge_data *, data, bridge_channel->tech_pvt, ao2_cleanup); if (!data) { return; } ast_channel_lock(bridge_channel->chan); ast_framehook_detach(bridge_channel->chan, data->id); data->detached = 1; ast_channel_unlock(bridge_channel->chan); bridge_channel->tech_pvt = NULL; }
void ast_jb_create_framehook(struct ast_channel *chan, struct ast_jb_conf *jb_conf, int prefer_existing) { struct jb_framedata *framedata; struct ast_datastore *datastore = NULL; struct ast_framehook_interface interface = { .version = AST_FRAMEHOOK_INTERFACE_VERSION, .event_cb = hook_event_cb, .destroy_cb = hook_destroy_cb, }; int i = 0; /* If disabled, strip any existing jitterbuffer and don't replace it. */ if (!strcasecmp(jb_conf->impl, "disabled")) { int *id; ast_channel_lock(chan); if ((datastore = ast_channel_datastore_find(chan, &jb_datastore, NULL))) { id = datastore->data; ast_framehook_detach(chan, *id); ast_channel_datastore_remove(chan, datastore); ast_datastore_free(datastore); } ast_channel_unlock(chan); return; } if (!(framedata = ast_calloc(1, sizeof(*framedata)))) { return; } if (jb_framedata_init(framedata, jb_conf)) { jb_framedata_destroy(framedata); return; } interface.data = framedata; ast_channel_lock(chan); i = ast_framehook_attach(chan, &interface); if (i >= 0) { int *id; if ((datastore = ast_channel_datastore_find(chan, &jb_datastore, NULL))) { /* There is already a jitterbuffer on the channel. */ if (prefer_existing) { /* We prefer the existing jitterbuffer, so remove the new one and keep the old one. */ ast_framehook_detach(chan, i); ast_channel_unlock(chan); return; } /* We prefer the new jitterbuffer, so strip the old one. */ id = datastore->data; ast_framehook_detach(chan, *id); ast_channel_datastore_remove(chan, datastore); ast_datastore_free(datastore); } if (!(datastore = ast_datastore_alloc(&jb_datastore, NULL))) { ast_framehook_detach(chan, i); ast_channel_unlock(chan); return; } if (!(id = ast_calloc(1, sizeof(int)))) { ast_datastore_free(datastore); ast_framehook_detach(chan, i); ast_channel_unlock(chan); return; } *id = i; /* Store off the id. The channel is still locked so it is safe to access this ptr. */ datastore->data = id; ast_channel_datastore_add(chan, datastore); ast_channel_set_fd(chan, AST_JITTERBUFFER_FD, framedata->timer_fd); } else { jb_framedata_destroy(framedata); framedata = NULL; } ast_channel_unlock(chan); }