const char *sip_route_add(struct sip_route *route, const char *uri, size_t len, int inserthead) { struct sip_route_hop *hop; if (!uri || len < 1 || uri[0] == '\0') { return NULL; } /* Expand len to include null terminator */ len++; /* ast_calloc is not needed because all fields are initialized in this block */ hop = ast_malloc(sizeof(struct sip_route_hop) + len); if (!hop) { return NULL; } ast_copy_string(hop->uri, uri, len); if (inserthead) { AST_LIST_INSERT_HEAD(&route->list, hop, list); route->type = route_invalidated; } else { if (sip_route_empty(route)) { route->type = route_invalidated; } AST_LIST_INSERT_TAIL(&route->list, hop, list); hop->list.next = NULL; } return hop->uri; }
static struct ast_frame *gen_readframe(struct gen_state *state) { struct ast_frame *f = NULL; struct ivr_localuser *u = state->u; if (u->abort_current_sound || (u->playing_silence && AST_LIST_FIRST(&u->playlist))) { gen_closestream(state); AST_LIST_LOCK(&u->playlist); gen_nextfile(state); AST_LIST_UNLOCK(&u->playlist); } if (!(state->stream && (f = ast_readframe(state->stream)))) { if (state->current) { AST_LIST_LOCK(&u->finishlist); AST_LIST_INSERT_TAIL(&u->finishlist, state->current, list); AST_LIST_UNLOCK(&u->finishlist); state->current = NULL; } if (!gen_nextfile(state)) f = ast_readframe(state->stream); } return f; }
static void app_control_register_rule( const struct stasis_app_control *control, struct app_control_rules *list, struct stasis_app_control_rule *obj) { SCOPED_AO2LOCK(lock, control->command_queue); AST_LIST_INSERT_TAIL(list, obj, next); }
static void *dialed_interface_duplicate(void *data) { struct ast_dialed_interface *di = NULL; AST_LIST_HEAD(, ast_dialed_interface) *old_list; AST_LIST_HEAD(, ast_dialed_interface) *new_list = NULL; if(!(old_list = data)) { return NULL; } if(!(new_list = ast_calloc(1, sizeof(*new_list)))) { return NULL; } AST_LIST_HEAD_INIT(new_list); AST_LIST_LOCK(old_list); AST_LIST_TRAVERSE(old_list, di, list) { struct ast_dialed_interface *di2 = ast_calloc(1, sizeof(*di2) + strlen(di->interface)); if(!di2) { AST_LIST_UNLOCK(old_list); dialed_interface_destroy(new_list); return NULL; } strcpy(di2->interface, di->interface); AST_LIST_INSERT_TAIL(new_list, di2, list); } AST_LIST_UNLOCK(old_list); return new_list; }
int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f) { struct ast_frame *begin_frame = f, *duped_frame = NULL, *frame_ptr; unsigned int x; /* In some cases, we can be passed a frame which has no data in it, but * which has a positive number of samples defined. Once such situation is * when a jitter buffer is in use and the jitter buffer interpolates a frame. * The frame it produces has data set to NULL, datalen set to 0, and samples * set to either 160 or 240. */ if (!f->data) { return 0; } if (f->subclass != AST_FORMAT_SLINEAR) { if (sf->trans && f->subclass != sf->format) { ast_translator_free_path(sf->trans); sf->trans = NULL; } if (!sf->trans) { if ((sf->trans = ast_translator_build_path(AST_FORMAT_SLINEAR, f->subclass)) == NULL) { ast_log(LOG_WARNING, "Cannot build a path from %s to slin\n", ast_getformatname(f->subclass)); return 0; } else { sf->format = f->subclass; } } if (!(begin_frame = ast_translate(sf->trans, f, 0))) return 0; duped_frame = ast_frdup(begin_frame); ast_frfree(begin_frame); if (!duped_frame) return 0; } else { if (!(duped_frame = ast_frdup(f))) return 0; } x = 0; AST_LIST_TRAVERSE(&sf->queue, frame_ptr, frame_list) x++; AST_LIST_INSERT_TAIL(&sf->queue, duped_frame, frame_list); sf->size += duped_frame->samples; return x; }
/*! * \internal * \brief Insert the header pointers into the linked list. * * For each header in the message, allocate a list entry, * clone the header, then insert the entry. */ static int insert_headers(pj_pool_t * pool, struct hdr_list *list, pjsip_msg * msg) { pjsip_hdr *hdr = msg->hdr.next; struct hdr_list_entry *le; while (hdr && hdr != &msg->hdr) { le = pj_pool_zalloc(pool, sizeof(struct hdr_list_entry)); le->hdr = pjsip_hdr_clone(pool, hdr); AST_LIST_INSERT_TAIL(list, le, nextptr); hdr = hdr->next; } return 0; }
static int at_fifo_queue_add_num (pvt_t* pvt, at_cmd_t cmd, at_res_t res, int num) { at_queue_t* e; if (!(e = ast_calloc (1, sizeof(*e)))) { return -1; } e->cmd = cmd; e->res = res; e->ptype = 1; e->param.num = num; AST_LIST_INSERT_TAIL (&pvt->at_queue, e, entry); ast_debug (4, "[%s] add command '%s' expected response '%s'\n", pvt->id, at_cmd2str (e->cmd), at_res2str (e->res)); return 0; }
/*! * \internal * \brief Implements PJSIP_HEADER 'add' by inserting the specified header into thge list. * * Retrieve the header_datastore from the session or create one if it doesn't exist. * Create and initialize the list if needed. * Create the pj_strs for name and value. * Create pjsip_msg and hdr_list_entry. * Add the entry to the list. */ static int add_header(void *obj) { struct header_data *data = obj; struct ast_sip_session *session = data->channel->session; pj_pool_t *pool = session->inv_session->dlg->pool; pj_str_t pj_header_name; pj_str_t pj_header_value; struct hdr_list_entry *le; struct hdr_list *list; RAII_VAR(struct ast_datastore *, datastore, ast_sip_session_get_datastore(session, header_datastore.type), ao2_cleanup); if (!datastore) { if (!(datastore = ast_sip_session_alloc_datastore(&header_datastore, header_datastore.type)) || !(datastore->data = pj_pool_alloc(pool, sizeof(struct hdr_list))) || ast_sip_session_add_datastore(session, datastore)) { ast_log(AST_LOG_ERROR, "Unable to create datastore for header functions.\n"); return -1; } AST_LIST_HEAD_INIT((struct hdr_list *) datastore->data); } ast_debug(1, "Adding header %s with value %s\n", data->header_name, data->header_value); pj_cstr(&pj_header_name, data->header_name); pj_cstr(&pj_header_value, data->header_value); le = pj_pool_zalloc(pool, sizeof(struct hdr_list_entry)); le->hdr = (pjsip_hdr *) pjsip_generic_string_hdr_create(pool, &pj_header_name, &pj_header_value); list = datastore->data; AST_LIST_INSERT_TAIL(list, le, nextptr); return 0; }
/*! * \internal * \brief Take sublists off of the given list. * * \param list Source list to remove sublists from the beginning of list. * \param sub Array of sublists to fill. (Lists are empty on entry.) * \param num_lists Number of lists to remove from the source list. * \param size Size of the sublists to remove. * \param remaining Remaining number of elements on the source list. * * \return Nothing */ static void mm_atexit_list_split(struct region_list *list, struct region_list sub[], size_t num_lists, size_t size, size_t *remaining) { int idx; for (idx = 0; idx < num_lists; ++idx) { size_t count; if (*remaining < size) { /* The remaining source list goes onto the sublist. */ AST_LIST_APPEND_LIST(&sub[idx], list, node); *remaining = 0; break; } /* Take a sublist off the beginning of the source list. */ *remaining -= size; for (count = size; count--;) { struct ast_region *reg; reg = AST_LIST_REMOVE_HEAD(list, node); AST_LIST_INSERT_TAIL(&sub[idx], reg, node); } } }
/*! * \internal * \brief Merge the given sorted sublists into sorted order onto the end of the list. * * \param list Merge sublists onto this list. * \param sub1 First sublist to merge. * \param sub2 Second sublist to merge. * * \return Nothing */ static void mm_atexit_list_merge(struct region_list *list, struct region_list *sub1, struct region_list *sub2) { struct ast_region *reg; for (;;) { if (AST_LIST_EMPTY(sub1)) { /* The remaining sublist goes onto the list. */ AST_LIST_APPEND_LIST(list, sub2, node); break; } if (AST_LIST_EMPTY(sub2)) { /* The remaining sublist goes onto the list. */ AST_LIST_APPEND_LIST(list, sub1, node); break; } if (mm_atexit_cmp(AST_LIST_FIRST(sub1), AST_LIST_FIRST(sub2)) <= 0) { reg = AST_LIST_REMOVE_HEAD(sub1, node); } else { reg = AST_LIST_REMOVE_HEAD(sub2, node); } AST_LIST_INSERT_TAIL(list, reg, node); } }
static int app_exec(struct ast_channel *chan, void *data) { struct ast_module_user *lu; struct playlist_entry *entry; const char *args = data; int child_stdin[2] = { 0,0 }; int child_stdout[2] = { 0,0 }; int child_stderr[2] = { 0,0 }; int res = -1; int test_available_fd = -1; int gen_active = 0; int pid; char *argv[32]; int argc = 1; char *buf, *command; FILE *child_commands = NULL; FILE *child_errors = NULL; FILE *child_events = NULL; struct ivr_localuser foo = { .playlist = AST_LIST_HEAD_INIT_VALUE, .finishlist = AST_LIST_HEAD_INIT_VALUE, }; struct ivr_localuser *u = &foo; sigset_t fullset, oldset; lu = ast_module_user_add(chan); sigfillset(&fullset); pthread_sigmask(SIG_BLOCK, &fullset, &oldset); u->abort_current_sound = 0; u->chan = chan; if (ast_strlen_zero(args)) { ast_log(LOG_WARNING, "ExternalIVR requires a command to execute\n"); ast_module_user_remove(lu); return -1; } buf = ast_strdupa(data); argc = ast_app_separate_args(buf, '|', argv, sizeof(argv) / sizeof(argv[0])); if (pipe(child_stdin)) { ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child input: %s\n", strerror(errno)); goto exit; } if (pipe(child_stdout)) { ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child output: %s\n", strerror(errno)); goto exit; } if (pipe(child_stderr)) { ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child errors: %s\n", strerror(errno)); goto exit; } if (chan->_state != AST_STATE_UP) { ast_answer(chan); } if (ast_activate_generator(chan, &gen, u) < 0) { ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n"); goto exit; } else gen_active = 1; pid = fork(); if (pid < 0) { ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno)); goto exit; } if (!pid) { /* child process */ int i; signal(SIGPIPE, SIG_DFL); pthread_sigmask(SIG_UNBLOCK, &fullset, NULL); if (ast_opt_high_priority) ast_set_priority(0); dup2(child_stdin[0], STDIN_FILENO); dup2(child_stdout[1], STDOUT_FILENO); dup2(child_stderr[1], STDERR_FILENO); for (i = STDERR_FILENO + 1; i < 1024; i++) close(i); execv(argv[0], argv); fprintf(stderr, "Failed to execute '%s': %s\n", argv[0], strerror(errno)); _exit(1); } else { /* parent process */ int child_events_fd = child_stdin[1]; int child_commands_fd = child_stdout[0]; int child_errors_fd = child_stderr[0]; struct ast_frame *f; int ms; int exception; int ready_fd; int waitfds[2] = { child_errors_fd, child_commands_fd }; struct ast_channel *rchan; pthread_sigmask(SIG_SETMASK, &oldset, NULL); close(child_stdin[0]); child_stdin[0] = 0; close(child_stdout[1]); child_stdout[1] = 0; close(child_stderr[1]); child_stderr[1] = 0; if (!(child_events = fdopen(child_events_fd, "w"))) { ast_chan_log(LOG_WARNING, chan, "Could not open stream for child events\n"); goto exit; } if (!(child_commands = fdopen(child_commands_fd, "r"))) { ast_chan_log(LOG_WARNING, chan, "Could not open stream for child commands\n"); goto exit; } if (!(child_errors = fdopen(child_errors_fd, "r"))) { ast_chan_log(LOG_WARNING, chan, "Could not open stream for child errors\n"); goto exit; } test_available_fd = open("/dev/null", O_RDONLY); setvbuf(child_events, NULL, _IONBF, 0); setvbuf(child_commands, NULL, _IONBF, 0); setvbuf(child_errors, NULL, _IONBF, 0); res = 0; while (1) { if (ast_test_flag(chan, AST_FLAG_ZOMBIE)) { ast_chan_log(LOG_NOTICE, chan, "Is a zombie\n"); res = -1; break; } if (ast_check_hangup(chan)) { ast_chan_log(LOG_NOTICE, chan, "Got check_hangup\n"); send_child_event(child_events, 'H', NULL, chan); res = -1; break; } ready_fd = 0; ms = 100; errno = 0; exception = 0; rchan = ast_waitfor_nandfds(&chan, 1, waitfds, 2, &exception, &ready_fd, &ms); if (!AST_LIST_EMPTY(&u->finishlist)) { AST_LIST_LOCK(&u->finishlist); while ((entry = AST_LIST_REMOVE_HEAD(&u->finishlist, list))) { send_child_event(child_events, 'F', entry->filename, chan); free(entry); } AST_LIST_UNLOCK(&u->finishlist); } if (rchan) { /* the channel has something */ f = ast_read(chan); if (!f) { ast_chan_log(LOG_NOTICE, chan, "Returned no frame\n"); send_child_event(child_events, 'H', NULL, chan); res = -1; break; } if (f->frametype == AST_FRAME_DTMF) { send_child_event(child_events, f->subclass, NULL, chan); if (u->option_autoclear) { if (!u->abort_current_sound && !u->playing_silence) send_child_event(child_events, 'T', NULL, chan); AST_LIST_LOCK(&u->playlist); while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) { send_child_event(child_events, 'D', entry->filename, chan); free(entry); } if (!u->playing_silence) u->abort_current_sound = 1; AST_LIST_UNLOCK(&u->playlist); } } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) { ast_chan_log(LOG_NOTICE, chan, "Got AST_CONTROL_HANGUP\n"); send_child_event(child_events, 'H', NULL, chan); ast_frfree(f); res = -1; break; } ast_frfree(f); } else if (ready_fd == child_commands_fd) { char input[1024]; if (exception || feof(child_commands)) { ast_chan_log(LOG_WARNING, chan, "Child process went away\n"); res = -1; break; } if (!fgets(input, sizeof(input), child_commands)) continue; command = ast_strip(input); ast_chan_log(LOG_DEBUG, chan, "got command '%s'\n", input); if (strlen(input) < 4) continue; if (input[0] == 'S') { if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) { ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]); send_child_event(child_events, 'Z', NULL, chan); strcpy(&input[2], "exception"); } if (!u->abort_current_sound && !u->playing_silence) send_child_event(child_events, 'T', NULL, chan); AST_LIST_LOCK(&u->playlist); while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) { send_child_event(child_events, 'D', entry->filename, chan); free(entry); } if (!u->playing_silence) u->abort_current_sound = 1; entry = make_entry(&input[2]); if (entry) AST_LIST_INSERT_TAIL(&u->playlist, entry, list); AST_LIST_UNLOCK(&u->playlist); } else if (input[0] == 'A') { if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) { ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]); send_child_event(child_events, 'Z', NULL, chan); strcpy(&input[2], "exception"); } entry = make_entry(&input[2]); if (entry) { AST_LIST_LOCK(&u->playlist); AST_LIST_INSERT_TAIL(&u->playlist, entry, list); AST_LIST_UNLOCK(&u->playlist); } } else if (input[0] == 'H') { ast_chan_log(LOG_NOTICE, chan, "Hanging up: %s\n", &input[2]); send_child_event(child_events, 'H', NULL, chan); break; } else if (input[0] == 'O') { if (!strcasecmp(&input[2], "autoclear")) u->option_autoclear = 1; else if (!strcasecmp(&input[2], "noautoclear")) u->option_autoclear = 0; else ast_chan_log(LOG_WARNING, chan, "Unknown option requested '%s'\n", &input[2]); } } else if (ready_fd == child_errors_fd) { char input[1024]; if (exception || (dup2(child_commands_fd, test_available_fd) == -1) || feof(child_errors)) { ast_chan_log(LOG_WARNING, chan, "Child process went away\n"); res = -1; break; } if (fgets(input, sizeof(input), child_errors)) { command = ast_strip(input); ast_chan_log(LOG_NOTICE, chan, "stderr: %s\n", command); } } else if ((ready_fd < 0) && ms) { if (errno == 0 || errno == EINTR) continue; ast_chan_log(LOG_WARNING, chan, "Wait failed (%s)\n", strerror(errno)); break; } } } exit: if (gen_active) ast_deactivate_generator(chan); if (child_events) fclose(child_events); if (child_commands) fclose(child_commands); if (child_errors) fclose(child_errors); if (test_available_fd > -1) { close(test_available_fd); } if (child_stdin[0]) close(child_stdin[0]); if (child_stdin[1]) close(child_stdin[1]); if (child_stdout[0]) close(child_stdout[0]); if (child_stdout[1]) close(child_stdout[1]); if (child_stderr[0]) close(child_stderr[0]); if (child_stderr[1]) close(child_stderr[1]); while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) free(entry); ast_module_user_remove(lu); return res; }
/*! \brief Initiate new call, part of PBX interface * dest is the dial string */ static int local_call(struct ast_channel *ast, const char *dest, int timeout) { struct local_pvt *p = ast_channel_tech_pvt(ast); int pvt_locked = 0; struct ast_channel *owner = NULL; struct ast_channel *chan = NULL; int res; struct ast_var_t *varptr; struct ast_var_t *clone_var; char *reduced_dest = ast_strdupa(dest); char *slash; const char *exten; const char *context; if (!p) { return -1; } /* since we are letting go of channel locks that were locked coming into * this function, then we need to give the tech pvt a ref */ ao2_ref(p, 1); ast_channel_unlock(ast); awesome_locking(p, &chan, &owner); pvt_locked = 1; if (owner != ast) { res = -1; goto return_cleanup; } if (!owner || !chan) { res = -1; goto return_cleanup; } /* * Note that cid_num and cid_name aren't passed in the ast_channel_alloc * call, so it's done here instead. * * All these failure points just return -1. The individual strings will * be cleared when we destroy the channel. */ ast_party_redirecting_copy(ast_channel_redirecting(chan), ast_channel_redirecting(owner)); ast_party_dialed_copy(ast_channel_dialed(chan), ast_channel_dialed(owner)); ast_connected_line_copy_to_caller(ast_channel_caller(chan), ast_channel_connected(owner)); ast_connected_line_copy_from_caller(ast_channel_connected(chan), ast_channel_caller(owner)); ast_channel_language_set(chan, ast_channel_language(owner)); ast_channel_accountcode_set(chan, ast_channel_accountcode(owner)); ast_channel_musicclass_set(chan, ast_channel_musicclass(owner)); ast_cdr_update(chan); ast_channel_cc_params_init(chan, ast_channel_get_cc_config_params(owner)); /* Make sure we inherit the AST_CAUSE_ANSWERED_ELSEWHERE if it's set on the queue/dial call request in the dialplan */ if (ast_channel_hangupcause(ast) == AST_CAUSE_ANSWERED_ELSEWHERE) { ast_channel_hangupcause_set(chan, AST_CAUSE_ANSWERED_ELSEWHERE); } /* copy the channel variables from the incoming channel to the outgoing channel */ /* Note that due to certain assumptions, they MUST be in the same order */ AST_LIST_TRAVERSE(ast_channel_varshead(owner), varptr, entries) { clone_var = ast_var_assign(varptr->name, varptr->value); if (clone_var) { AST_LIST_INSERT_TAIL(ast_channel_varshead(chan), clone_var, entries); } }
/*! * \internal * \brief Handle COLP and redirecting conditions. * \since 12.0.0 * * \param p Unreal private structure. * \param ast Channel indicating the condition. * \param condition What is being indicated. * * \retval 0 on success. * \retval -1 on error. */ static int unreal_colp_redirect_indicate(struct ast_unreal_pvt *p, struct ast_channel *ast, int condition) { struct ast_channel *my_chan; struct ast_channel *my_owner; struct ast_channel *this_channel; struct ast_channel *the_other_channel; int isoutbound; int res = 0; unsigned char frame_data[1024]; struct ast_frame f = { .frametype = AST_FRAME_CONTROL, .subclass.integer = condition, .data.ptr = frame_data, }; /* * A connected line update frame may only contain a partial * amount of data, such as just a source, or just a ton, and not * the full amount of information. However, the collected * information is all stored in the outgoing channel's * connectedline structure, so when receiving a connected line * update on an outgoing unreal channel, we need to transmit the * collected connected line information instead of whatever * happens to be in this control frame. The same applies for * redirecting information, which is why it is handled here as * well. */ ast_channel_unlock(ast); ast_unreal_lock_all(p, &my_chan, &my_owner); isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p); if (isoutbound) { this_channel = p->chan; the_other_channel = p->owner; } else { this_channel = p->owner; the_other_channel = p->chan; } if (the_other_channel) { if (condition == AST_CONTROL_CONNECTED_LINE) { ast_connected_line_copy_to_caller(ast_channel_caller(the_other_channel), ast_channel_connected(this_channel)); f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data), ast_channel_connected(this_channel), NULL); } else { f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data), ast_channel_redirecting(this_channel), NULL); } } if (my_chan) { ast_channel_unlock(my_chan); ast_channel_unref(my_chan); } if (my_owner) { ast_channel_unlock(my_owner); ast_channel_unref(my_owner); } if (the_other_channel) { res = unreal_queue_frame(p, isoutbound, &f, ast, 0); } ao2_unlock(p); ast_channel_lock(ast); return res; } int ast_unreal_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen) { struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast); int res = 0; if (!p) { return -1; } ao2_ref(p, 1); /* ref for unreal_queue_frame */ switch (condition) { case AST_CONTROL_CONNECTED_LINE: case AST_CONTROL_REDIRECTING: res = unreal_colp_redirect_indicate(p, ast, condition); break; case AST_CONTROL_HOLD: if (ast_test_flag(p, AST_UNREAL_MOH_INTERCEPT)) { ast_moh_start(ast, data, NULL); break; } res = unreal_queue_indicate(p, ast, condition, data, datalen); break; case AST_CONTROL_UNHOLD: if (ast_test_flag(p, AST_UNREAL_MOH_INTERCEPT)) { ast_moh_stop(ast); break; } res = unreal_queue_indicate(p, ast, condition, data, datalen); break; default: res = unreal_queue_indicate(p, ast, condition, data, datalen); break; } ao2_ref(p, -1); return res; } int ast_unreal_digit_begin(struct ast_channel *ast, char digit) { struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast); int res = -1; struct ast_frame f = { AST_FRAME_DTMF_BEGIN, }; int isoutbound; if (!p) { return -1; } ao2_ref(p, 1); /* ref for unreal_queue_frame */ ao2_lock(p); isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p); f.subclass.integer = digit; res = unreal_queue_frame(p, isoutbound, &f, ast, 0); ao2_unlock(p); ao2_ref(p, -1); return res; } int ast_unreal_digit_end(struct ast_channel *ast, char digit, unsigned int duration) { struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast); int res = -1; struct ast_frame f = { AST_FRAME_DTMF_END, }; int isoutbound; if (!p) { return -1; } ao2_ref(p, 1); /* ref for unreal_queue_frame */ ao2_lock(p); isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p); f.subclass.integer = digit; f.len = duration; res = unreal_queue_frame(p, isoutbound, &f, ast, 0); ao2_unlock(p); ao2_ref(p, -1); return res; } int ast_unreal_sendtext(struct ast_channel *ast, const char *text) { struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast); int res = -1; struct ast_frame f = { AST_FRAME_TEXT, }; int isoutbound; if (!p) { return -1; } ao2_ref(p, 1); /* ref for unreal_queue_frame */ ao2_lock(p); isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p); f.data.ptr = (char *) text; f.datalen = strlen(text) + 1; res = unreal_queue_frame(p, isoutbound, &f, ast, 0); ao2_unlock(p); ao2_ref(p, -1); return res; } int ast_unreal_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen) { struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast); int res = -1; struct ast_frame f = { AST_FRAME_HTML, }; int isoutbound; if (!p) { return -1; } ao2_ref(p, 1); /* ref for unreal_queue_frame */ ao2_lock(p); isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p); f.subclass.integer = subclass; f.data.ptr = (char *)data; f.datalen = datalen; res = unreal_queue_frame(p, isoutbound, &f, ast, 0); ao2_unlock(p); ao2_ref(p, -1); return res; } void ast_unreal_call_setup(struct ast_channel *semi1, struct ast_channel *semi2) { struct ast_var_t *varptr; struct ast_var_t *clone_var; /* * Note that cid_num and cid_name aren't passed in the * ast_channel_alloc calls in ast_unreal_new_channels(). It's * done here instead. */ ast_party_redirecting_copy(ast_channel_redirecting(semi2), ast_channel_redirecting(semi1)); ast_party_dialed_copy(ast_channel_dialed(semi2), ast_channel_dialed(semi1)); ast_connected_line_copy_to_caller(ast_channel_caller(semi2), ast_channel_connected(semi1)); ast_connected_line_copy_from_caller(ast_channel_connected(semi2), ast_channel_caller(semi1)); ast_channel_language_set(semi2, ast_channel_language(semi1)); ast_channel_accountcode_set(semi2, ast_channel_accountcode(semi1)); ast_channel_musicclass_set(semi2, ast_channel_musicclass(semi1)); ast_channel_cc_params_init(semi2, ast_channel_get_cc_config_params(semi1)); /* * Make sure we inherit the AST_CAUSE_ANSWERED_ELSEWHERE if it's * set on the queue/dial call request in the dialplan. */ if (ast_channel_hangupcause(semi1) == AST_CAUSE_ANSWERED_ELSEWHERE) { ast_channel_hangupcause_set(semi2, AST_CAUSE_ANSWERED_ELSEWHERE); } /* * Copy the channel variables from the semi1 channel to the * outgoing channel. * * Note that due to certain assumptions, they MUST be in the * same order. */ AST_LIST_TRAVERSE(ast_channel_varshead(semi1), varptr, entries) { clone_var = ast_var_assign(varptr->name, varptr->value); if (clone_var) { AST_LIST_INSERT_TAIL(ast_channel_varshead(semi2), clone_var, entries); } } ast_channel_datastore_inherit(semi1, semi2); }
/** \brief Build ast_speech_result based on the NLSML result */ static struct ast_speech_result* uni_recog_speech_result_build(uni_speech_t *uni_speech, const apt_str_t *nlsml_result, mrcp_version_e mrcp_version) { float confidence; const char *grammar; const char *text; struct ast_speech_result *speech_result; struct ast_speech_result *first_speech_result; nlsml_interpretation_t *interpretation; nlsml_instance_t *instance; nlsml_input_t *input; int interpretation_count; int instance_count; apr_pool_t *pool = mrcp_application_session_pool_get(uni_speech->session); nlsml_result_t *result = nlsml_result_parse(nlsml_result->buf, nlsml_result->length, pool); if(!result) { ast_log(LOG_WARNING, "(%s) Failed to parse NLSML result: %s\n",uni_speech->name,nlsml_result->buf); return NULL; } #if 1 /* enable/disable debug output of parsed results */ nlsml_result_trace(result, pool); #endif first_speech_result = NULL; #if AST_VERSION_AT_LEAST(1,6,0) AST_LIST_HEAD_NOLOCK(, ast_speech_result) speech_results; AST_LIST_HEAD_INIT_NOLOCK(&speech_results); #else struct ast_speech_result *last_speech_result = NULL; #endif interpretation_count = 0; interpretation = nlsml_first_interpretation_get(result); while(interpretation) { input = nlsml_interpretation_input_get(interpretation); if(!input) { ast_log(LOG_WARNING, "(%s) Failed to get NLSML input\n",uni_speech->name); continue; } instance_count = 0; instance = nlsml_interpretation_first_instance_get(interpretation); if(!instance) { ast_log(LOG_WARNING, "(%s) Failed to get NLSML instance\n",uni_speech->name); continue; } confidence = nlsml_interpretation_confidence_get(interpretation); grammar = nlsml_interpretation_grammar_get(interpretation); if(grammar) { const char session_token[] = "session:"; char *str = strstr(grammar,session_token); if(str) { grammar = str + sizeof(session_token) - 1; } } do { nlsml_instance_swi_suppress(instance); text = nlsml_instance_content_generate(instance, pool); speech_result = ast_calloc(sizeof(struct ast_speech_result), 1); if(text) speech_result->text = strdup(text); speech_result->score = confidence * 100; if(grammar) speech_result->grammar = strdup(grammar); speech_result->nbest_num = interpretation_count; if(!first_speech_result) first_speech_result = speech_result; #if AST_VERSION_AT_LEAST(1,6,0) AST_LIST_INSERT_TAIL(&speech_results, speech_result, list); #else speech_result->next = last_speech_result; last_speech_result = speech_result; #endif ast_log(LOG_NOTICE, "(%s) Speech result[%d/%d]: %s, score: %d, grammar: %s\n", uni_speech->name, interpretation_count, instance_count, speech_result->text, speech_result->score, speech_result->grammar); instance_count++; instance = nlsml_interpretation_next_instance_get(interpretation, instance); } while(instance); interpretation_count++; interpretation = nlsml_next_interpretation_get(result, interpretation); } return first_speech_result; }