/*! * \brief Get the next SMDI message from the queue. * \param iface a pointer to the interface to use. * * This function pulls the first unexpired message from the SMDI message queue * on the specified interface. It will purge all expired SMDI messages before * returning. * * \return the next SMDI message, or NULL if there were no pending messages. */ extern struct ast_smdi_mwi_message *ast_smdi_mwi_message_pop(struct ast_smdi_interface *iface) { struct ast_smdi_mwi_message *mwi_msg = ASTOBJ_CONTAINER_UNLINK_START(&iface->mwi_q); struct timeval now; long elapsed = 0; /* purge old messages */ now = ast_tvnow(); while (mwi_msg) { elapsed = ast_tvdiff_ms(now, mwi_msg->timestamp); if (elapsed > iface->msg_expiry) { /* found an expired message */ ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy); ast_log(LOG_NOTICE, "Purged expired message from %s SMDI MWI message queue. Message was %ld milliseconds too old.", iface->name, elapsed - iface->msg_expiry); mwi_msg = ASTOBJ_CONTAINER_UNLINK_START(&iface->mwi_q); } else { /* good message, return it */ break; } } return mwi_msg; }
static int waituntil_exec(struct ast_channel *chan, void *data) { int res; double fraction; struct timeval future = { 0, }; struct timeval tv = ast_tvnow(); int msec; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "WaitUntil requires an argument(epoch)\n"); pbx_builtin_setvar_helper(chan, "WAITUNTILSTATUS", "FAILURE"); return 0; } if (sscanf(data, "%ld%lf", (long *)&future.tv_sec, &fraction) == 0) { ast_log(LOG_WARNING, "WaitUntil called with non-numeric argument\n"); pbx_builtin_setvar_helper(chan, "WAITUNTILSTATUS", "FAILURE"); return 0; } future.tv_usec = fraction * 1000000; if ((msec = ast_tvdiff_ms(future, tv)) < 0) { ast_log(LOG_NOTICE, "WaitUntil called in the past (now %ld, arg %ld)\n", (long)tv.tv_sec, (long)future.tv_sec); pbx_builtin_setvar_helper(chan, "WAITUNTILSTATUS", "PAST"); return 0; } if ((res = ast_safe_sleep(chan, msec))) pbx_builtin_setvar_helper(chan, "WAITUNTILSTATUS", "HANGUP"); else pbx_builtin_setvar_helper(chan, "WAITUNTILSTATUS", "OK"); return res; }
/*! * \brief Set a dial timeout interval hook on the channel. * * The absolute time that the timeout should occur is stored on * a datastore on the channel. This time is converted into a relative * number of milliseconds in the future. Then an interval hook is set * to trigger in that number of milliseconds. * * \pre chan is locked * * \param chan The channel on which to set the interval hook */ static void set_interval_hook(struct ast_channel *chan) { struct ast_datastore *datastore; struct timeval *hangup_time; int64_t ms; struct ast_bridge_channel *bridge_channel; datastore = ast_channel_datastore_find(chan, &timeout_datastore, NULL); if (!datastore) { return; } hangup_time = datastore->data; ms = ast_tvdiff_ms(*hangup_time, ast_tvnow()); bridge_channel = ast_channel_get_bridge_channel(chan); if (!bridge_channel) { return; } if (ast_bridge_interval_hook(bridge_channel->features, 0, ms > 0 ? ms : 1, bridge_timeout, NULL, NULL, 0)) { return; } ast_queue_frame(bridge_channel->chan, &ast_null_frame); }
/* * Receive a string of DTMF digits where the length of the digit string is known in advance. Do not give preferential * treatment to any digit value, and allow separate time out values to be specified for the first digit and all subsequent * digits. * * Returns 0 if all digits successfully received. * Returns 1 if a digit time out occurred * Returns -1 if the caller hung up or there was a channel error. * */ static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int length, int fdto, int sdto) { int res = 0; int i = 0; int r; struct ast_frame *f; struct timeval lastdigittime; lastdigittime = ast_tvnow(); for (;;) { /* if outa time, leave */ if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) > ((i > 0) ? sdto : fdto)) { ast_verb(4, "AlarmReceiver: DTMF Digit Timeout on %s\n", ast_channel_name(chan)); ast_debug(1,"AlarmReceiver: DTMF timeout on chan %s\n",ast_channel_name(chan)); res = 1; break; } if ((r = ast_waitfor(chan, -1)) < 0) { ast_debug(1, "Waitfor returned %d\n", r); continue; } f = ast_read(chan); if (f == NULL) { res = -1; break; } /* If they hung up, leave */ if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP)) { if (f->data.uint32) { ast_channel_hangupcause_set(chan, f->data.uint32); } ast_frfree(f); res = -1; break; } /* if not DTMF, just do it again */ if (f->frametype != AST_FRAME_DTMF) { ast_frfree(f); continue; } digit_string[i++] = f->subclass.integer; /* save digit */ ast_frfree(f); /* If we have all the digits we expect, leave */ if(i >= length) break; lastdigittime = ast_tvnow(); } digit_string[i] = '\0'; /* Nul terminate the end of the digit string */ return res; }
int ast_sip_sched_task_get_next_run(struct ast_sip_sched_task *schtd) { int delay; struct timeval since_when; struct timeval now; if (!ao2_ref_and_lock(schtd)) { return -1; } if (schtd->interval) { delay = schtd->interval; now = ast_tvnow(); if (schtd->flags & AST_SIP_SCHED_TASK_DELAY) { since_when = schtd->is_running ? now : schtd->last_end; } else { since_when = schtd->last_start.tv_sec ? schtd->last_start : schtd->when_queued; } delay -= ast_tvdiff_ms(now, since_when); delay = delay < 0 ? 0 : delay; } else { delay = -1; } ao2_unlock_and_unref(schtd); return delay; }
static void __verboser(const char *stuff, int opos, int replacelast, int complete) { char *s2[2]; struct timeval tv; int ms; s2[0] = (char *)stuff; s2[1] = NULL; gtk_clist_freeze(GTK_CLIST(verb)); if (replacelast) gtk_clist_remove(GTK_CLIST(verb), GTK_CLIST(verb)->rows - 1); gtk_clist_append(GTK_CLIST(verb), s2); if (!ast_tvzero(last)) { gdk_threads_leave(); gettimeofday(&tv, NULL); if (cleanupid > -1) gtk_timeout_remove(cleanupid); ms = ast_tvdiff_ms(tv, last); if (ms < 100) { /* We just got a message within 100ms, so just schedule an update in the near future */ cleanupid = gtk_timeout_add(200, cleanup, NULL); } else { cleanup(&cleanupid); } last = tv; } else { gettimeofday(&last, NULL); } }
/*! \brief Observer callback for when a contact is created */ static void contact_expiration_observer_created(const void *object) { const struct ast_sip_contact *contact = object; struct contact_expiration *expiration; int expires = MAX(0, ast_tvdiff_ms(contact->expiration_time, ast_tvnow())); if (ast_tvzero(contact->expiration_time)) { return; } expiration = ao2_alloc_options(sizeof(*expiration), contact_expiration_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK); if (!expiration) { return; } expiration->contact = (struct ast_sip_contact*)contact; ao2_ref(expiration->contact, +1); ao2_ref(expiration, +1); if ((expiration->sched = ast_sched_add(sched, expires, contact_expiration_expire, expiration)) < 0) { ao2_ref(expiration, -1); ast_log(LOG_ERROR, "Scheduled expiration for contact '%s' could not be performed, contact may persist past life\n", ast_sorcery_object_get_id(contact)); } else { ao2_link(contact_autoexpire, expiration); } ao2_ref(expiration, -1); }
static int measurenoise(struct ast_channel *chan, int ms, char *who) { int res=0; int mssofar; int noise=0; int samples=0; int x; short *foo; struct timeval start; struct ast_frame *f; struct ast_format *rformat; rformat = ao2_bump(ast_channel_readformat(chan)); if (ast_set_read_format(chan, ast_format_slin)) { ast_log(LOG_NOTICE, "Unable to set to linear mode!\n"); ao2_cleanup(rformat); return -1; } start = ast_tvnow(); for(;;) { mssofar = ast_tvdiff_ms(ast_tvnow(), start); if (mssofar > ms) break; res = ast_waitfor(chan, ms - mssofar); if (res < 1) break; f = ast_read(chan); if (!f) { res = -1; break; } if ((f->frametype == AST_FRAME_VOICE) && (ast_format_cmp(f->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)) { foo = (short *)f->data.ptr; for (x=0;x<f->samples;x++) { noise += abs(foo[x]); samples++; } } ast_frfree(f); } if (rformat) { if (ast_set_read_format(chan, rformat)) { ast_log(LOG_NOTICE, "Unable to restore original format!\n"); ao2_ref(rformat, -1); return -1; } ao2_ref(rformat, -1); } if (res < 0) return res; if (!samples) { ast_log(LOG_NOTICE, "No samples were received from the other side!\n"); return -1; } ast_debug(1, "%s: Noise: %d, samples: %d, avg: %d\n", who, noise, samples, noise / samples); return (noise / samples); }
/*! * \brief Receive a fixed length DTMF string. * * \note Doesn't give preferential treatment to any digit, * \note allow different timeout values for the first and all subsequent digits * * \param chan Asterisk Channel * \param digit_string Digits String * \param buf_size The size of the Digits String buffer * \param expected Digits expected for this message type * \param received Pointer to number of digits received so far * * \retval 0 if all digits were successfully received * \retval 1 if a timeout occurred * \retval -1 if the caller hung up or on channel errors */ static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int buf_size, int expected, int *received) { int rtn = 0; int r; struct ast_frame *f; struct timeval lastdigittime; lastdigittime = ast_tvnow(); while (*received < expected && *received < buf_size - 1) { /* If timed out, leave */ if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) > ((*received > 0) ? sdtimeout : fdtimeout)) { ast_verb(4, "AlarmReceiver: DTMF Digit Timeout on %s\n", ast_channel_name(chan)); ast_debug(1, "AlarmReceiver: DTMF timeout on chan %s\n", ast_channel_name(chan)); rtn = 1; break; } if ((r = ast_waitfor(chan, -1)) < 0) { ast_debug(1, "Waitfor returned %d\n", r); continue; } if ((f = ast_read(chan)) == NULL) { rtn = -1; break; } /* If they hung up, leave */ if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP)) { if (f->data.uint32) { ast_channel_hangupcause_set(chan, f->data.uint32); } ast_frfree(f); rtn = -1; break; } /* If not DTMF, just do it again */ if (f->frametype != AST_FRAME_DTMF) { ast_frfree(f); continue; } /* Save digit */ digit_string[(*received)++] = f->subclass.integer; ast_frfree(f); lastdigittime = ast_tvnow(); } /* Null terminate the end of the digit_string */ digit_string[*received] = '\0'; return rtn; }
static long get_now(struct ast_jb *jb, struct timeval *when) { struct timeval now; if (!when) { when = &now; gettimeofday(when, NULL); } return ast_tvdiff_ms(*when, jb->timebase); }
static int expire_requests(void *object, void *arg, int flags) { struct unidentified_request *unid = object; int *maxage = arg; int64_t ms = ast_tvdiff_ms(ast_tvnow(), unid->first_seen); if (ms > (*maxage) * 2 * 1000) { return CMP_MATCH; } return 0; }
/*! \brief Callback function which deletes a contact if it has expired or sets up auto-expiry */ static int contact_expiration_setup(void *obj, void *arg, int flags) { struct ast_sip_contact *contact = obj; int expires = MAX(0, ast_tvdiff_ms(contact->expiration_time, ast_tvnow())); if (!expires) { ast_sorcery_delete(ast_sip_get_sorcery(), contact); } else { contact_expiration_observer_created(contact); } return 0; }
/*! \brief Internal callback function which deletes and unlinks any expired contacts */ static int contact_expire(void *obj, void *arg, int flags) { struct ast_sip_contact *contact = obj; /* If the contact has not yet expired it is valid */ if (ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) > 0) { return 0; } ast_sip_location_delete_contact(contact); return CMP_MATCH; }
/* * This function is run in the context of the serializer. * It runs the task with a simple call and reschedules based on the result. */ static int run_task(void *data) { RAII_VAR(struct ast_sip_sched_task *, schtd, ao2_bump(data), ao2_cleanup); int res; int delay; ao2_lock(schtd); schtd->last_start = ast_tvnow(); schtd->is_running = 1; schtd->run_count++; ao2_unlock(schtd); res = schtd->task(schtd->task_data); ao2_lock(schtd); schtd->is_running = 0; schtd->last_end = ast_tvnow(); /* * Don't restart if the task returned 0 or if the interval * was set to 0 while the task was running */ if (!res || !schtd->interval) { schtd->interval = 0; ao2_unlock(schtd); ao2_unlink(tasks, schtd); return -1; } if (schtd->flags & AST_SIP_SCHED_TASK_VARIABLE) { schtd->interval = res; } if (schtd->flags & AST_SIP_SCHED_TASK_DELAY) { delay = schtd->interval; } else { delay = schtd->interval - (ast_tvdiff_ms(schtd->last_end, schtd->last_start) % schtd->interval); } schtd->current_scheduler_id = ast_sched_add(scheduler_context, delay, push_to_serializer, (const void *)schtd); if (schtd->current_scheduler_id < 0) { schtd->interval = 0; ao2_unlock(schtd); ao2_unlink(tasks, schtd); return -1; } ao2_unlock(schtd); return 0; }
static void check_endpoint(pjsip_rx_data *rdata, struct unidentified_request *unid, const char *name) { int64_t ms = ast_tvdiff_ms(ast_tvnow(), unid->first_seen); ao2_wrlock(unid); unid->count++; if (ms < (unidentified_period * 1000) && unid->count >= unidentified_count) { log_failed_request(rdata, "No matching endpoint found", unid->count, ms); ast_sip_report_invalid_endpoint(name, rdata); } ao2_unlock(unid); }
/*! \brief complete a buffer from the local video source. * Called by get_video_frames(), in turn called by the video thread. */ static struct fbuf_t *grabber_read(struct video_out_desc *v) { struct timeval now = ast_tvnow(); if (v->grabber == NULL) /* not initialized */ return 0; /* check if it is time to read */ if (ast_tvzero(v->last_frame)) v->last_frame = now; if (ast_tvdiff_ms(now, v->last_frame) < 1000/v->fps) return 0; /* too early */ v->last_frame = now; /* XXX actually, should correct for drift */ return v->grabber->read(v->grabber_data); }
/*! \brief Internal function which adds a contact to a response */ static int registrar_add_contact(void *obj, void *arg, int flags) { struct ast_sip_contact *contact = obj; pjsip_tx_data *tdata = arg; pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(tdata->pool); pj_str_t uri; pj_strdup2_with_null(tdata->pool, &uri, contact->uri); hdr->uri = pjsip_parse_uri(tdata->pool, uri.ptr, uri.slen, PJSIP_PARSE_URI_AS_NAMEADDR); hdr->expires = ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) / 1000; pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr); return 0; }
/*! \brief Observer callback for when a contact is updated */ static void contact_expiration_observer_updated(const void *object) { const struct ast_sip_contact *contact = object; struct contact_expiration *expiration; int expires = MAX(0, ast_tvdiff_ms(contact->expiration_time, ast_tvnow())); expiration = ao2_find(contact_autoexpire, ast_sorcery_object_get_id(contact), OBJ_SEARCH_KEY); if (!expiration) { return; } AST_SCHED_REPLACE_UNREF(expiration->sched, sched, expires, contact_expiration_expire, expiration, ao2_cleanup(expiration), ao2_cleanup(expiration), ao2_ref(expiration, +1)); ao2_ref(expiration, -1); }
/*! \brief complete a buffer from the specified local video source. * Called by get_video_frames(), in turn called by the video thread. * * \param dev = video environment descriptor * \param fps = frame per seconds, for every device * * returns: * - NULL on falure * - reference to the device buffer on success */ static struct fbuf_t *grabber_read(struct video_device *dev, int fps) { struct timeval now = ast_tvnow(); if (dev->grabber == NULL) /* not initialized */ return NULL; /* the last_frame field in this row of the device table (dev) is always initialized, it is set during the parsing of the config file, and never unset, function fill_device_table(). */ /* check if it is time to read */ if (ast_tvdiff_ms(now, dev->last_frame) < 1000/fps) return NULL; /* too early */ dev->last_frame = now; /* XXX actually, should correct for drift */ return dev->grabber->read(dev->grabber_data); }
static void limits_interval_playback(struct ast_bridge_channel *bridge_channel, struct ast_bridge_features_limits *limits, const char *file) { if (!strcasecmp(file, "timeleft")) { unsigned int remaining = ast_tvdiff_ms(limits->quitting_time, ast_tvnow()) / 1000; unsigned int min; unsigned int sec; if (remaining <= 0) { return; } if ((remaining / 60) > 1) { min = remaining / 60; sec = remaining % 60; } else { min = 0; sec = remaining; } ast_stream_and_wait(bridge_channel->chan, "vm-youhave", AST_DIGIT_NONE); if (min) { ast_say_number(bridge_channel->chan, min, AST_DIGIT_NONE, ast_channel_language(bridge_channel->chan), NULL); ast_stream_and_wait(bridge_channel->chan, "queue-minutes", AST_DIGIT_NONE); } if (sec) { ast_say_number(bridge_channel->chan, sec, AST_DIGIT_NONE, ast_channel_language(bridge_channel->chan), NULL); ast_stream_and_wait(bridge_channel->chan, "queue-seconds", AST_DIGIT_NONE); } } else { ast_stream_and_wait(bridge_channel->chan, file, AST_DIGIT_NONE); } /* * It may be necessary to resume music on hold after we finish * playing the announcment. */ if (ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_MOH)) { const char *latest_musicclass; ast_channel_lock(bridge_channel->chan); latest_musicclass = ast_strdupa(ast_channel_latest_musicclass(bridge_channel->chan)); ast_channel_unlock(bridge_channel->chan); ast_moh_start(bridge_channel->chan, latest_musicclass, NULL); } }
static void calc_cost(struct ast_translator *t, int samples) { int sofar=0; struct ast_translator_pvt *pvt; struct ast_frame *f, *out; struct timeval start; int cost; if(!samples) samples = 1; /* If they don't make samples, give them a terrible score */ if (!t->sample) { ast_log(LOG_WARNING, "Translator '%s' does not produce sample frames.\n", t->name); t->cost = 99999; return; } pvt = t->newpvt(); if (!pvt) { ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name); t->cost = 99999; return; } start = ast_tvnow(); /* Call the encoder until we've processed one second of time */ while(sofar < samples * 8000) { f = t->sample(); if (!f) { ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name); t->destroy(pvt); t->cost = 99999; return; } t->framein(pvt, f); ast_frfree(f); while((out = t->frameout(pvt))) { sofar += out->samples; ast_frfree(out); } } cost = ast_tvdiff_ms(ast_tvnow(), start); t->destroy(pvt); t->cost = cost / samples; if (!t->cost) t->cost = 1; }
static int timeout_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { struct timeval myt; if (!chan) return -1; if (!data) { ast_log(LOG_ERROR, "Must specify type of timeout to get.\n"); return -1; } switch (*data) { case 'a': case 'A': if (ast_tvzero(*ast_channel_whentohangup(chan))) { ast_copy_string(buf, "0", len); } else { myt = ast_tvnow(); snprintf(buf, len, "%.3f", ast_tvdiff_ms(*ast_channel_whentohangup(chan), myt) / 1000.0); } break; case 'r': case 'R': if (ast_channel_pbx(chan)) { snprintf(buf, len, "%.3f", ast_channel_pbx(chan)->rtimeoutms / 1000.0); } break; case 'd': case 'D': if (ast_channel_pbx(chan)) { snprintf(buf, len, "%.3f", ast_channel_pbx(chan)->dtimeoutms / 1000.0); } break; default: ast_log(LOG_ERROR, "Unknown timeout type specified.\n"); return -1; } return 0; }
/*! * \brief Get the next SMDI message from the queue. * \param iface a pointer to the interface to use. * \param timeout the time to wait before returning in milliseconds. * * This function pulls a message from the SMDI message queue on the specified * interface. If no message is available this function will wait the specified * amount of time before returning. * * \return the next SMDI message, or NULL if there were no pending messages and * the timeout has expired. */ extern struct ast_smdi_mwi_message *ast_smdi_mwi_message_wait(struct ast_smdi_interface *iface, int timeout) { struct timeval start; long diff = 0; struct ast_smdi_mwi_message *msg; start = ast_tvnow(); while (diff < timeout) { if ((msg = ast_smdi_mwi_message_pop(iface))) return msg; /* check timeout */ diff = ast_tvdiff_ms(ast_tvnow(), start); } return (ast_smdi_mwi_message_pop(iface)); }
int ast_sched_wait(struct sched_context *con) { /* * Return the number of milliseconds * until the next scheduled event */ int ms; DEBUG(ast_log(LOG_DEBUG, "ast_sched_wait()\n")); ast_mutex_lock(&con->lock); if (!con->schedq) { ms = -1; } else { ms = ast_tvdiff_ms(con->schedq->when, ast_tvnow()); if (ms < 0) ms = 0; } ast_mutex_unlock(&con->lock); return ms; }
static int cli_unid_print_body(void *obj, void *arg, int flags) { struct unidentified_request *unid = obj; struct ast_sip_cli_context *context = arg; int indent; int flexwidth; int64_t ms = ast_tvdiff_ms(ast_tvnow(), unid->first_seen); ast_assert(context->output_buffer != NULL); indent = CLI_INDENT_TO_SPACES(context->indent_level); flexwidth = CLI_LAST_TABSTOP - 4; ast_str_append(&context->output_buffer, 0, "%*s: %-*.*s %7d %10.3f\n", indent, "Request", flexwidth, flexwidth, unid->src_name, unid->count, ms / 1000.0); return 0; }
/*! * \retval 0 no timer tick needed * \retval non-zero write to the timing pipe needed */ static int check_timer(struct pthread_timer *timer) { struct timeval now; if (timer->state == TIMER_STATE_IDLE) { return 0; } now = ast_tvnow(); if (timer->tick_count < (ast_tvdiff_ms(now, timer->start) / timer->interval)) { timer->tick_count++; if (!timer->tick_count) { /* Handle overflow. */ timer->start = now; } return 1; } return 0; }
/*! * \brief Router callback for \ref stasis_cache_update messages. * \param data Data pointer given when added to router. * \param sub This subscription. * \param topic The topic the message was posted to. This is not necessarily the * topic you subscribed to, since messages may be forwarded between * topics. * \param message The message itself. */ static void updates(void *data, struct stasis_subscription *sub, struct stasis_message *message) { /* Since this came from a message router, we know the type of the * message. We can cast the data without checking its type. */ struct stasis_cache_update *update = stasis_message_data(message); /* We're only interested in channel snapshots, so check the type * of the underlying message. */ if (ast_channel_snapshot_type() != update->type) { return; } /* There are three types of cache updates. * !old && new -> Initial cache entry * old && new -> Updated cache entry * old && !new -> Cache entry removed. */ if (!update->old_snapshot && update->new_snapshot) { /* Initial cache entry; count a channel creation */ ast_statsd_log("channels.count", AST_STATSD_COUNTER, 1); } else if (update->old_snapshot && !update->new_snapshot) { /* Cache entry removed. Compute the age of the channel and post * that, as well as decrementing the channel count. */ struct ast_channel_snapshot *last; int64_t age; last = stasis_message_data(update->old_snapshot); age = ast_tvdiff_ms(*stasis_message_timestamp(message), last->creationtime); ast_statsd_log("channels.calltime", AST_STATSD_TIMER, age); /* And decrement the channel count */ ast_statsd_log("channels.count", AST_STATSD_COUNTER, -1); } }
int ast_poll2(struct pollfd *pArray, unsigned long n_fds, struct timeval *tv) { #if !defined(AST_POLL_COMPAT) struct timeval start = ast_tvnow(); #if defined(HAVE_PPOLL) struct timespec ts = { tv ? tv->tv_sec : 0, tv ? tv->tv_usec * 1000 : 0 }; int res = ppoll(pArray, n_fds, tv ? &ts : NULL, NULL); #else int res = poll(pArray, n_fds, tv ? tv->tv_sec * 1000 + tv->tv_usec / 1000 : -1); #endif struct timeval after = ast_tvnow(); if (res > 0 && tv && ast_tvdiff_ms(ast_tvadd(*tv, start), after) > 0) { *tv = ast_tvsub(*tv, ast_tvsub(after, start)); } else if (res > 0 && tv) { *tv = ast_tv(0, 0); } return res; #else ast_fdset read_descs, write_descs, except_descs; int ready_descriptors, max_fd = 0; FD_ZERO(&read_descs); FD_ZERO(&write_descs); FD_ZERO(&except_descs); if (pArray) { max_fd = map_poll_spec(pArray, n_fds, &read_descs, &write_descs, &except_descs); } ready_descriptors = ast_select(max_fd + 1, &read_descs, &write_descs, &except_descs, tv); if (ready_descriptors >= 0) { map_select_results(pArray, n_fds, &read_descs, &write_descs, &except_descs); } return ready_descriptors; #endif }
static void *hook_launch_thread(void *data) { struct hook_thread_arg *arg = data; struct ast_variable hook_id = { .name = "HOOK_ID", .value = arg->hook_id, }; struct ast_variable chan_name_var = { .name = "HOOK_CHANNEL", .value = arg->chan_name, .next = &hook_id, }; ast_pbx_outgoing_exten("Local", NULL, full_exten_name, 60, arg->context, arg->exten, 1, NULL, AST_OUTGOING_NO_WAIT, NULL, NULL, &chan_name_var, NULL, NULL, 1, NULL); hook_thread_arg_destroy(arg); return NULL; } static struct hook_thread_arg *hook_thread_arg_alloc(struct ast_channel *chan, struct hook_state *state) { struct hook_thread_arg *arg; if (!(arg = ast_calloc(1, sizeof(*arg)))) { return NULL; } ast_channel_lock(chan); arg->chan_name = ast_strdup(ast_channel_name(chan)); ast_channel_unlock(chan); if (!arg->chan_name) { hook_thread_arg_destroy(arg); return NULL; } if (ast_asprintf(&arg->hook_id, "%u", state->hook_id) == -1) { hook_thread_arg_destroy(arg); return NULL; } if (!(arg->context = ast_strdup(state->context))) { hook_thread_arg_destroy(arg); return NULL; } if (!(arg->exten = ast_strdup(state->exten))) { hook_thread_arg_destroy(arg); return NULL; } return arg; } static int do_hook(struct ast_channel *chan, struct hook_state *state) { pthread_t t; struct hook_thread_arg *arg; int res; if (!(arg = hook_thread_arg_alloc(chan, state))) { return -1; } /* * We don't want to block normal frame processing *at all* while we kick * this off, so do it in a new thread. */ res = ast_pthread_create_detached_background(&t, NULL, hook_launch_thread, arg); if (res != 0) { hook_thread_arg_destroy(arg); } return res; } static int hook_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction) { struct hook_state *state = (struct hook_state *) audiohook; /* trust me. */ struct timeval now; int res = 0; if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE || state->disabled) { return 0; } now = ast_tvnow(); if (ast_tvdiff_ms(now, state->last_hook) > state->interval * 1000) { if ((res = do_hook(chan, state))) { const char *name; ast_channel_lock(chan); name = ast_strdupa(ast_channel_name(chan)); ast_channel_unlock(chan); ast_log(LOG_WARNING, "Failed to run hook on '%s'\n", name); } state->last_hook = now; } return res; } static struct hook_state *hook_state_alloc(const char *context, const char *exten, unsigned int interval, unsigned int hook_id) { struct hook_state *state; if (!(state = ast_calloc(1, sizeof(*state)))) { return NULL; } state->context = ast_strdup(context); state->exten = ast_strdup(exten); state->interval = interval; state->hook_id = hook_id; ast_audiohook_init(&state->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, AST_MODULE, AST_AUDIOHOOK_MANIPULATE_ALL_RATES); state->audiohook.manipulate_callback = hook_callback; return state; } static int init_hook(struct ast_channel *chan, const char *context, const char *exten, unsigned int interval, unsigned int hook_id) { struct hook_state *state; struct ast_datastore *datastore; char uid[32]; snprintf(uid, sizeof(uid), "%u", hook_id); if (!(datastore = ast_datastore_alloc(&hook_datastore, uid))) { return -1; } ast_module_ref(ast_module_info->self); if (!(state = hook_state_alloc(context, exten, interval, hook_id))) { ast_datastore_free(datastore); return -1; } datastore->data = state; ast_channel_lock(chan); ast_channel_datastore_add(chan, datastore); ast_audiohook_attach(chan, &state->audiohook); ast_channel_unlock(chan); return 0; } static int hook_on(struct ast_channel *chan, const char *data, unsigned int hook_id) { char *parse = ast_strdupa(S_OR(data, "")); AST_DECLARE_APP_ARGS(args, AST_APP_ARG(context); AST_APP_ARG(exten); AST_APP_ARG(interval); );
/*! * \brief Convert a file from one format to another * \param e CLI entry * \param cmd command number * \param a list of cli arguments * \retval CLI_SUCCESS on success. * \retval CLI_SHOWUSAGE or CLI_FAILURE on failure. */ static char *handle_cli_file_convert(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { char *ret = CLI_FAILURE; struct ast_filestream *fs_in = NULL, *fs_out = NULL; struct ast_frame *f; struct timeval start; int cost; char *file_in = NULL, *file_out = NULL; char *name_in, *ext_in, *name_out, *ext_out; switch (cmd) { case CLI_INIT: e->command = "file convert"; e->usage = "Usage: file convert <file_in> <file_out>\n" " Convert from file_in to file_out. If an absolute path\n" " is not given, the default Asterisk sounds directory\n" " will be used.\n\n" " Example:\n" " file convert tt-weasels.gsm tt-weasels.ulaw\n"; return NULL; case CLI_GENERATE: return NULL; } /* ugly, can be removed when CLI entries have ast_module pointers */ ast_module_ref(ast_module_info->self); if (a->argc != 4 || ast_strlen_zero(a->argv[2]) || ast_strlen_zero(a->argv[3])) { ret = CLI_SHOWUSAGE; goto fail_out; } file_in = ast_strdupa(a->argv[2]); file_out = ast_strdupa(a->argv[3]); if (split_ext(file_in, &name_in, &ext_in)) { ast_cli(a->fd, "'%s' is an invalid filename!\n", a->argv[2]); goto fail_out; } if (!(fs_in = ast_readfile(name_in, ext_in, NULL, O_RDONLY, 0, 0))) { ast_cli(a->fd, "Unable to open input file: %s\n", a->argv[2]); goto fail_out; } if (split_ext(file_out, &name_out, &ext_out)) { ast_cli(a->fd, "'%s' is an invalid filename!\n", a->argv[3]); goto fail_out; } if (!(fs_out = ast_writefile(name_out, ext_out, NULL, O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) { ast_cli(a->fd, "Unable to open output file: %s\n", a->argv[3]); goto fail_out; } start = ast_tvnow(); while ((f = ast_readframe(fs_in))) { if (ast_writestream(fs_out, f)) { ast_frfree(f); ast_cli(a->fd, "Failed to convert %s.%s to %s.%s!\n", name_in, ext_in, name_out, ext_out); goto fail_out; } ast_frfree(f); } cost = ast_tvdiff_ms(ast_tvnow(), start); ast_cli(a->fd, "Converted %s.%s to %s.%s in %dms\n", name_in, ext_in, name_out, ext_out, cost); ret = CLI_SUCCESS; fail_out: if (fs_out) { ast_closestream(fs_out); if (ret != CLI_SUCCESS) ast_filedelete(name_out, ext_out); } if (fs_in) ast_closestream(fs_in); ast_module_unref(ast_module_info->self); return ret; }