struct ast_format *ast_format_attribute_set(const struct ast_format *format, const char *name, const char *value) { const struct ast_format_interface *interface = format->interface; if (!interface) { struct format_interface *format_interface = ao2_find(interfaces, format->codec->name, OBJ_SEARCH_KEY); if (format_interface) { interface = format_interface->interface; ao2_ref(format_interface, -1); } } if (!interface || !interface->format_attribute_set) { return ao2_bump((struct ast_format*)format); } return interface->format_attribute_set(format, name, value); }
static int route_table_add(struct route_table *table, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data) { struct stasis_message_route route; int res; ast_assert(callback != NULL); ast_assert(route_table_find(table, message_type) == NULL); route.message_type = ao2_bump(message_type); route.callback = callback; route.data = data; res = AST_VECTOR_APPEND(table, route); if (res) { ROUTE_TABLE_ELEM_CLEANUP(route); } return res; }
struct ast_format *ast_format_joint(const struct ast_format *format1, const struct ast_format *format2) { const struct ast_format_interface *interface; if (format1->codec != format2->codec) { return NULL; } /* If the two formats are the same structure OR if the codec is the same and no attributes * exist we can immediately return a format with reference count bumped up, since they are * the same. */ if ((ast_format_cmp(format1, format2) == AST_FORMAT_CMP_EQUAL && !format1->attribute_data && !format2->attribute_data)) { return ao2_bump((struct ast_format*)format1); } interface = format1->interface ? format1->interface : format2->interface; /* If there is attribute data on either there has to be an interface */ return interface->format_get_joint(format1, format2); }
struct ast_format *ast_format_create_named(const char *format_name, struct ast_codec *codec) { struct ast_format *format; struct format_interface *format_interface; format = ao2_t_alloc_options(sizeof(*format), format_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK, S_OR(codec->description, "")); if (!format) { return NULL; } format->name = format_name; format->codec = ao2_bump(codec); format->channel_count = 1; format_interface = ao2_find(interfaces, codec->name, OBJ_SEARCH_KEY); if (format_interface) { format->interface = format_interface->interface; ao2_ref(format_interface, -1); } return format; }
static struct mwi_subscription *mwi_subscription_alloc(struct ast_sip_endpoint *endpoint, unsigned int is_solicited, struct ast_sip_subscription *sip_sub) { struct mwi_subscription *sub; const char *endpoint_id = ast_sorcery_object_get_id(endpoint); sub = ao2_alloc(sizeof(*sub) + strlen(endpoint_id), mwi_subscription_destructor); if (!sub) { return NULL; } /* Safe strcpy */ strcpy(sub->id, endpoint_id); /* Unsolicited MWI doesn't actually result in a SIP subscription being * created. This is because a SIP subscription associates with a dialog. * Most devices expect unsolicited MWI NOTIFYs to appear out of dialog. If * they receive an in-dialog MWI NOTIFY (i.e. with a to-tag), then they * will reject the NOTIFY with a 481, thus resulting in message-waiting * state not being updated on the device */ if (is_solicited) { sub->sip_sub = ao2_bump(sip_sub); } sub->stasis_subs = ao2_container_alloc(STASIS_BUCKETS, stasis_sub_hash, stasis_sub_cmp); if (!sub->stasis_subs) { ao2_cleanup(sub); return NULL; } sub->is_solicited = is_solicited; ast_debug(3, "Created %s MWI subscription for endpoint %s\n", is_solicited ? "solicited" : "unsolicited", sub->id); return sub; }
int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time, const char *path_info, const char *user_agent, struct ast_sip_endpoint *endpoint) { char name[MAX_OBJECT_FIELD * 2 + 3]; RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup); char hash[33]; ast_md5_hash(hash, uri); snprintf(name, sizeof(name), "%s;@%s", ast_sorcery_object_get_id(aor), hash); if (!(contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", name))) { return -1; } ast_string_field_set(contact, uri, uri); contact->expiration_time = expiration_time; contact->qualify_frequency = aor->qualify_frequency; contact->qualify_timeout = aor->qualify_timeout; contact->authenticate_qualify = aor->authenticate_qualify; if (path_info && aor->support_path) { ast_string_field_set(contact, path, path_info); } if (!ast_strlen_zero(aor->outbound_proxy)) { ast_string_field_set(contact, outbound_proxy, aor->outbound_proxy); } if (!ast_strlen_zero(user_agent)) { ast_string_field_set(contact, user_agent, user_agent); } contact->endpoint = ao2_bump(endpoint); return ast_sorcery_create(ast_sip_get_sorcery(), contact); }
static int mp3_exec(struct ast_channel *chan, const char *data) { int res=0; int fds[2]; int ms = -1; int pid = -1; RAII_VAR(struct ast_format *, owriteformat, NULL, ao2_cleanup); int timeout = 2000; struct timeval next; struct ast_frame *f; struct myframe { struct ast_frame f; char offset[AST_FRIENDLY_OFFSET]; short frdata[160]; } myf = { .f = { 0, }, }; struct ast_format * native_format; unsigned int sampling_rate; struct ast_format * write_format; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "MP3 Playback requires an argument (filename)\n"); return -1; } if (pipe(fds)) { ast_log(LOG_WARNING, "Unable to create pipe\n"); return -1; } ast_stopstream(chan); native_format = ast_format_cap_get_format(ast_channel_nativeformats(chan), 0); sampling_rate = ast_format_get_sample_rate(native_format); write_format = ast_format_cache_get_slin_by_rate(sampling_rate); owriteformat = ao2_bump(ast_channel_writeformat(chan)); res = ast_set_write_format(chan, write_format); if (res < 0) { ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); return -1; } myf.f.frametype = AST_FRAME_VOICE; myf.f.subclass.format = write_format; myf.f.mallocd = 0; myf.f.offset = AST_FRIENDLY_OFFSET; myf.f.src = __PRETTY_FUNCTION__; myf.f.delivery.tv_sec = 0; myf.f.delivery.tv_usec = 0; myf.f.data.ptr = myf.frdata; res = mp3play(data, sampling_rate, fds[1]); if (!strncasecmp(data, "http://", 7)) { timeout = 10000; } /* Wait 1000 ms first */ next = ast_tvnow(); next.tv_sec += 1; if (res >= 0) { pid = res; /* Order is important -- there's almost always going to be mp3... we want to prioritize the user */ for (;;) { ms = ast_tvdiff_ms(next, ast_tvnow()); if (ms <= 0) { res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout); if (res > 0) { myf.f.datalen = res; myf.f.samples = res / 2; if (ast_write(chan, &myf.f) < 0) { res = -1; break; } } else { ast_debug(1, "No more mp3\n"); res = 0; break; } next = ast_tvadd(next, ast_samp2tv(myf.f.samples, sampling_rate)); } else { ms = ast_waitfor(chan, ms); if (ms < 0) { ast_debug(1, "Hangup detected\n"); res = -1; break; } if (ms) { f = ast_read(chan); if (!f) { ast_debug(1, "Null frame == hangup() detected\n"); res = -1; break; } if (f->frametype == AST_FRAME_DTMF) { ast_debug(1, "User pressed a key\n"); ast_frfree(f); res = 0; break; } ast_frfree(f); } } } } close(fds[0]); close(fds[1]); if (pid > -1) kill(pid, SIGKILL); if (!res && owriteformat) ast_set_write_format(chan, owriteformat); ast_frfree(&myf.f); return res; }
static int do_waiting(struct ast_channel *chan, int timereqd, time_t waitstart, int timeout, int wait_for_silence) { struct ast_frame *f = NULL; int dsptime = 0; RAII_VAR(struct ast_format *, rfmt, NULL, ao2_cleanup); int res = 0; struct ast_dsp *sildet; /* silence detector dsp */ time_t now; /*Either silence or noise calc depending on wait_for_silence flag*/ int (*ast_dsp_func)(struct ast_dsp*, struct ast_frame*, int*) = wait_for_silence ? ast_dsp_silence : ast_dsp_noise; rfmt = ao2_bump(ast_channel_readformat(chan)); if ((res = ast_set_read_format(chan, ast_format_slin)) < 0) { ast_log(LOG_WARNING, "Unable to set channel to linear mode, giving up\n"); return -1; } /* Create the silence detector */ if (!(sildet = ast_dsp_new())) { ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); return -1; } ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE)); /* Await silence... */ for (;;) { /* Start with no silence received */ dsptime = 0; res = ast_waitfor(chan, timereqd); /* Must have gotten a hangup; let's exit */ if (res < 0) { pbx_builtin_setvar_helper(chan, "WAITSTATUS", "HANGUP"); break; } /* We waited and got no frame; sounds like digital silence or a muted digital channel */ if (res == 0) { dsptime = timereqd; } else { /* Looks like we did get a frame, so let's check it out */ if (!(f = ast_read(chan))) { pbx_builtin_setvar_helper(chan, "WAITSTATUS", "HANGUP"); break; } if (f->frametype == AST_FRAME_VOICE) { ast_dsp_func(sildet, f, &dsptime); } ast_frfree(f); } ast_debug(1, "Got %dms %s < %dms required\n", dsptime, wait_for_silence ? "silence" : "noise", timereqd); if (dsptime >= timereqd) { ast_verb(3, "Exiting with %dms %s >= %dms required\n", dsptime, wait_for_silence ? "silence" : "noise", timereqd); /* Ended happily with silence */ res = 1; pbx_builtin_setvar_helper(chan, "WAITSTATUS", wait_for_silence ? "SILENCE" : "NOISE"); ast_debug(1, "WAITSTATUS was set to %s\n", wait_for_silence ? "SILENCE" : "NOISE"); break; } if (timeout && (difftime(time(&now), waitstart) >= timeout)) { pbx_builtin_setvar_helper(chan, "WAITSTATUS", "TIMEOUT"); ast_debug(1, "WAITSTATUS was set to TIMEOUT\n"); res = 0; break; } } if (rfmt && ast_set_read_format(chan, rfmt)) { ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_format_get_name(rfmt), ast_channel_name(chan)); } ast_dsp_free(sildet); return res; }
static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, int length, char *intkeys) { int res = 0; int fds[2]; int needed = 0; struct ast_format *owriteformat; struct ast_frame *f; struct myframe { struct ast_frame f; char offset[AST_FRIENDLY_OFFSET]; char frdata[2048]; } myf = { .f = { 0, }, }; if (pipe(fds)) { ast_log(LOG_WARNING, "Unable to create pipe\n"); return -1; } /* Answer if it's not already going */ if (ast_channel_state(chan) != AST_STATE_UP) ast_answer(chan); ast_stopstream(chan); ast_indicate(chan, -1); owriteformat = ao2_bump(ast_channel_writeformat(chan)); res = ast_set_write_format(chan, ast_format_slin); if (res < 0) { ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); ao2_cleanup(owriteformat); return -1; } myf.f.frametype = AST_FRAME_VOICE; myf.f.subclass.format = ast_format_slin; myf.f.offset = AST_FRIENDLY_OFFSET; myf.f.src = __PRETTY_FUNCTION__; myf.f.data.ptr = myf.frdata; res = send_waveform_to_fd(waveform, length, fds[1]); if (res >= 0) { /* Order is important -- there's almost always going to be mp3... we want to prioritize the user */ for (;;) { res = ast_waitfor(chan, 1000); if (res < 1) { res = -1; break; } f = ast_read(chan); if (!f) { ast_log(LOG_WARNING, "Null frame == hangup() detected\n"); res = -1; break; } if (f->frametype == AST_FRAME_DTMF) { ast_debug(1, "User pressed a key\n"); if (intkeys && strchr(intkeys, f->subclass.integer)) { res = f->subclass.integer; ast_frfree(f); break; } } if (f->frametype == AST_FRAME_VOICE) { /* Treat as a generator */ needed = f->samples * 2; if (needed > sizeof(myf.frdata)) { ast_log(LOG_WARNING, "Only able to deliver %d of %d requested samples\n", (int)sizeof(myf.frdata) / 2, needed/2); needed = sizeof(myf.frdata); } res = read(fds[0], myf.frdata, needed); if (res > 0) { myf.f.datalen = res; myf.f.samples = res / 2; if (ast_write(chan, &myf.f) < 0) { res = -1; ast_frfree(f); break; } if (res < needed) { /* last frame */ ast_debug(1, "Last frame\n"); res = 0; ast_frfree(f); break; } } else { ast_debug(1, "No more waveform\n"); res = 0; } } ast_frfree(f); } } close(fds[0]); close(fds[1]); if (!res && owriteformat) ast_set_write_format(chan, owriteformat); ao2_cleanup(owriteformat); return res; }
struct stasis_app *app_create(const char *name, stasis_app_cb handler, void *data, enum stasis_app_subscription_model subscription_model) { RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup); size_t size; int res = 0; ast_assert(name != NULL); ast_assert(handler != NULL); ast_verb(1, "Creating Stasis app '%s'\n", name); size = sizeof(*app) + strlen(name) + 1; app = ao2_alloc_options(size, app_dtor, AO2_ALLOC_OPT_LOCK_MUTEX); if (!app) { return NULL; } app->subscription_model = subscription_model; app->forwards = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_MUTEX, AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT, forwards_sort, NULL); if (!app->forwards) { return NULL; } app->topic = stasis_topic_create(name); if (!app->topic) { return NULL; } app->bridge_router = stasis_message_router_create(ast_bridge_topic_all()); if (!app->bridge_router) { return NULL; } res |= stasis_message_router_add(app->bridge_router, ast_bridge_merge_message_type(), bridge_merge_handler, app); res |= stasis_message_router_add(app->bridge_router, ast_blind_transfer_type(), bridge_blind_transfer_handler, app); res |= stasis_message_router_add(app->bridge_router, ast_attended_transfer_type(), bridge_attended_transfer_handler, app); res |= stasis_message_router_set_default(app->bridge_router, bridge_default_handler, app); if (res != 0) { return NULL; } /* Bridge router holds a reference */ ao2_ref(app, +1); app->router = stasis_message_router_create(app->topic); if (!app->router) { return NULL; } res |= stasis_message_router_add_cache_update(app->router, ast_bridge_snapshot_type(), sub_bridge_update_handler, app); res |= stasis_message_router_add_cache_update(app->router, ast_channel_snapshot_type(), sub_channel_update_handler, app); res |= stasis_message_router_add_cache_update(app->router, ast_endpoint_snapshot_type(), sub_endpoint_update_handler, app); res |= stasis_message_router_set_default(app->router, sub_default_handler, app); if (res != 0) { return NULL; } /* Router holds a reference */ ao2_ref(app, +1); strncpy(app->name, name, size - sizeof(*app)); app->handler = handler; app->data = ao2_bump(data); ao2_ref(app, +1); return app; }
struct stasis_app *app_create(const char *name, stasis_app_cb handler, void *data, enum stasis_app_subscription_model subscription_model) { RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup); size_t size; int res = 0; size_t context_size = strlen("stasis-") + strlen(name) + 1; char context_name[context_size]; ast_assert(name != NULL); ast_assert(handler != NULL); ast_verb(1, "Creating Stasis app '%s'\n", name); size = sizeof(*app) + strlen(name) + 1; app = ao2_alloc_options(size, app_dtor, AO2_ALLOC_OPT_LOCK_MUTEX); if (!app) { return NULL; } app->subscription_model = subscription_model; app->forwards = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_MUTEX, AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT, forwards_sort, NULL); if (!app->forwards) { return NULL; } app->topic = stasis_topic_create(name); if (!app->topic) { return NULL; } app->bridge_router = stasis_message_router_create(ast_bridge_topic_all()); if (!app->bridge_router) { return NULL; } res |= stasis_message_router_add(app->bridge_router, ast_bridge_merge_message_type(), bridge_merge_handler, app); res |= stasis_message_router_add(app->bridge_router, ast_blind_transfer_type(), bridge_blind_transfer_handler, app); res |= stasis_message_router_add(app->bridge_router, ast_attended_transfer_type(), bridge_attended_transfer_handler, app); res |= stasis_message_router_add(app->bridge_router, stasis_subscription_change_type(), bridge_subscription_change_handler, app); if (res != 0) { return NULL; } /* Bridge router holds a reference */ ao2_ref(app, +1); app->router = stasis_message_router_create(app->topic); if (!app->router) { return NULL; } res |= stasis_message_router_add(app->router, ast_bridge_snapshot_type(), sub_bridge_update_handler, app); res |= stasis_message_router_add(app->router, ast_channel_snapshot_type(), sub_channel_update_handler, app); res |= stasis_message_router_add_cache_update(app->router, ast_endpoint_snapshot_type(), sub_endpoint_update_handler, app); res |= stasis_message_router_add(app->router, stasis_subscription_change_type(), sub_subscription_change_handler, app); stasis_message_router_set_formatters_default(app->router, sub_default_handler, app, STASIS_SUBSCRIPTION_FORMATTER_JSON); if (res != 0) { return NULL; } /* Router holds a reference */ ao2_ref(app, +1); strncpy(app->name, name, size - sizeof(*app)); app->handler = handler; app->data = ao2_bump(data); /* Create a context, a match-all extension, and a 'h' extension for this application. Note that * this should only be done if a context does not already exist. */ strcpy(context_name, "stasis-"); strcat(context_name, name); if (!ast_context_find(context_name)) { if (!ast_context_find_or_create(NULL, NULL, context_name, "res_stasis")) { ast_log(LOG_WARNING, "Could not create context '%s' for Stasis application '%s'\n", context_name, name); } else { ast_add_extension(context_name, 0, "_.", 1, NULL, NULL, "Stasis", ast_strdup(name), ast_free_ptr, "res_stasis"); ast_add_extension(context_name, 0, "h", 1, NULL, NULL, "NoOp", NULL, NULL, "res_stasis"); } } else { ast_log(LOG_WARNING, "Not creating context '%s' for Stasis application '%s' because it already exists\n", context_name, name); } ao2_ref(app, +1); return app; }
static int ices_exec(struct ast_channel *chan, const char *data) { int res = 0; int fds[2]; int ms = -1; int pid = -1; int flags; struct ast_format *oreadformat; struct ast_frame *f; char filename[256]=""; char *c; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "ICES requires an argument (configfile.xml)\n"); return -1; } if (pipe(fds)) { ast_log(LOG_WARNING, "Unable to create pipe\n"); return -1; } flags = fcntl(fds[1], F_GETFL); fcntl(fds[1], F_SETFL, flags | O_NONBLOCK); ast_stopstream(chan); if (ast_channel_state(chan) != AST_STATE_UP) res = ast_answer(chan); if (res) { close(fds[0]); close(fds[1]); ast_log(LOG_WARNING, "Answer failed!\n"); return -1; } oreadformat = ao2_bump(ast_channel_readformat(chan)); res = ast_set_read_format(chan, ast_format_slin); if (res < 0) { close(fds[0]); close(fds[1]); ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); ao2_cleanup(oreadformat); return -1; } if (((char *)data)[0] == '/') ast_copy_string(filename, (char *) data, sizeof(filename)); else snprintf(filename, sizeof(filename), "%s/%s", ast_config_AST_CONFIG_DIR, (char *)data); /* Placeholder for options */ c = strchr(filename, '|'); if (c) *c = '\0'; res = icesencode(filename, fds[0]); if (res >= 0) { pid = res; for (;;) { /* Wait for audio, and stream */ ms = ast_waitfor(chan, -1); if (ms < 0) { ast_debug(1, "Hangup detected\n"); res = -1; break; } f = ast_read(chan); if (!f) { ast_debug(1, "Null frame == hangup() detected\n"); res = -1; break; } if (f->frametype == AST_FRAME_VOICE) { res = write(fds[1], f->data.ptr, f->datalen); if (res < 0) { if (errno != EAGAIN) { ast_log(LOG_WARNING, "Write failed to pipe: %s\n", strerror(errno)); res = -1; ast_frfree(f); break; } } } ast_frfree(f); } } close(fds[0]); close(fds[1]); if (pid > -1) kill(pid, SIGKILL); if (!res && oreadformat) ast_set_read_format(chan, oreadformat); ao2_cleanup(oreadformat); return res; }
static int transmit_audio(fax_session *s) { int res = -1; struct ast_format *original_read_fmt; struct ast_format *original_write_fmt = NULL; fax_state_t fax; t30_state_t *t30state; struct ast_frame *inf = NULL; int last_state = 0; struct timeval now, start, state_change; enum ast_t38_state t38_state; struct ast_control_t38_parameters t38_parameters = { .version = 0, .max_ifp = 800, .rate = AST_T38_RATE_14400, .rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF, .fill_bit_removal = 1, /* * spandsp has API calls to support MMR and JBIG transcoding, but they aren't * implemented quite yet... so don't offer them to the remote endpoint * .transcoding_mmr = 1, * .transcoding_jbig = 1, */ }; /* if in called party mode, try to use T.38 */ if (s->caller_mode == FALSE) { /* check if we are already in T.38 mode (unlikely), or if we can request * a switch... if so, request it now and wait for the result, rather * than starting an audio FAX session that will have to be cancelled */ if ((t38_state = ast_channel_get_t38_state(s->chan)) == T38_STATE_NEGOTIATED) { return 1; } else if ((t38_state != T38_STATE_UNAVAILABLE) && (t38_parameters.request_response = AST_T38_REQUEST_NEGOTIATE, (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0))) { /* wait up to five seconds for negotiation to complete */ unsigned int timeout = 5000; int ms; ast_debug(1, "Negotiating T.38 for receive on %s\n", ast_channel_name(s->chan)); while (timeout > 0) { ms = ast_waitfor(s->chan, 1000); if (ms < 0) { ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", ast_channel_name(s->chan)); return -1; } if (!ms) { /* nothing happened */ if (timeout > 0) { timeout -= 1000; continue; } else { ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", ast_channel_name(s->chan)); break; } } if (!(inf = ast_read(s->chan))) { return -1; } if ((inf->frametype == AST_FRAME_CONTROL) && (inf->subclass.integer == AST_CONTROL_T38_PARAMETERS) && (inf->datalen == sizeof(t38_parameters))) { struct ast_control_t38_parameters *parameters = inf->data.ptr; switch (parameters->request_response) { case AST_T38_NEGOTIATED: ast_debug(1, "Negotiated T.38 for receive on %s\n", ast_channel_name(s->chan)); res = 1; break; case AST_T38_REFUSED: ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", ast_channel_name(s->chan)); break; default: ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", ast_channel_name(s->chan)); break; } ast_frfree(inf); if (res == 1) { return 1; } else { break; } } ast_frfree(inf); } } } #if SPANDSP_RELEASE_DATE >= 20080725 /* for spandsp shaphots 0.0.6 and higher */ t30state = &fax.t30; #else /* for spandsp release 0.0.5 */ t30state = &fax.t30_state; #endif original_read_fmt = ao2_bump(ast_channel_readformat(s->chan)); res = ast_set_read_format(s->chan, ast_format_slin); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n"); goto done; } original_write_fmt = ao2_bump(ast_channel_writeformat(s->chan)); res = ast_set_write_format(s->chan, ast_format_slin); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n"); goto done; } /* Initialize T30 terminal */ fax_init(&fax, s->caller_mode); /* Setup logging */ set_logging(&fax.logging); set_logging(&t30state->logging); /* Configure terminal */ set_local_info(t30state, s); set_file(t30state, s); set_ecm(t30state, TRUE); fax_set_transmit_on_idle(&fax, TRUE); t30_set_phase_e_handler(t30state, phase_e_handler, s); start = state_change = ast_tvnow(); ast_activate_generator(s->chan, &generator, &fax); while (!s->finished) { inf = NULL; if ((res = ast_waitfor(s->chan, 25)) < 0) { ast_debug(1, "Error waiting for a frame\n"); break; } /* Watchdog */ now = ast_tvnow(); if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) { ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n"); res = -1; break; } if (!res) { /* There was timeout waiting for a frame. Loop around and wait again */ continue; } /* There is a frame available. Get it */ res = 0; if (!(inf = ast_read(s->chan))) { ast_debug(1, "Channel hangup\n"); res = -1; break; } ast_debug(10, "frame %d/%s, len=%d\n", inf->frametype, ast_format_get_name(inf->subclass.format), inf->datalen); /* Check the frame type. Format also must be checked because there is a chance that a frame in old format was already queued before we set channel format to slinear so it will still be received by ast_read */ if (inf->frametype == AST_FRAME_VOICE && (ast_format_cmp(inf->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)) { if (fax_rx(&fax, inf->data.ptr, inf->samples) < 0) { /* I know fax_rx never returns errors. The check here is for good style only */ ast_log(LOG_WARNING, "fax_rx returned error\n"); res = -1; break; } if (last_state != t30state->state) { state_change = ast_tvnow(); last_state = t30state->state; } } else if ((inf->frametype == AST_FRAME_CONTROL) && (inf->subclass.integer == AST_CONTROL_T38_PARAMETERS)) { struct ast_control_t38_parameters *parameters = inf->data.ptr; if (parameters->request_response == AST_T38_NEGOTIATED) { /* T38 switchover completed */ s->t38parameters = *parameters; ast_debug(1, "T38 negotiated, finishing audio loop\n"); res = 1; break; } else if (parameters->request_response == AST_T38_REQUEST_NEGOTIATE) { t38_parameters.request_response = AST_T38_NEGOTIATED; ast_debug(1, "T38 request received, accepting\n"); /* Complete T38 switchover */ ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)); /* Do not break audio loop, wait until channel driver finally acks switchover * with AST_T38_NEGOTIATED */ } } ast_frfree(inf); inf = NULL; } ast_debug(1, "Loop finished, res=%d\n", res); if (inf) ast_frfree(inf); ast_deactivate_generator(s->chan); /* If we are switching to T38, remove phase E handler. Otherwise it will be executed by t30_terminate, display diagnostics and set status variables although no transmittion has taken place yet. */ if (res > 0) { t30_set_phase_e_handler(t30state, NULL, NULL); } t30_terminate(t30state); fax_release(&fax); done: if (original_write_fmt) { if (ast_set_write_format(s->chan, original_write_fmt) < 0) ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", ast_channel_name(s->chan)); ao2_ref(original_write_fmt, -1); } if (original_read_fmt) { if (ast_set_read_format(s->chan, original_read_fmt) < 0) ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", ast_channel_name(s->chan)); ao2_ref(original_read_fmt, -1); } return res; } static int transmit_t38(fax_session *s) { int res = 0; t38_terminal_state_t t38; struct ast_frame *inf = NULL; int last_state = 0; struct timeval now, start, state_change, last_frame; t30_state_t *t30state; t38_core_state_t *t38state; #if SPANDSP_RELEASE_DATE >= 20080725 /* for spandsp shaphots 0.0.6 and higher */ t30state = &t38.t30; t38state = &t38.t38_fe.t38; #else /* for spandsp releases 0.0.5 */ t30state = &t38.t30_state; t38state = &t38.t38; #endif /* Initialize terminal */ memset(&t38, 0, sizeof(t38)); if (t38_terminal_init(&t38, s->caller_mode, t38_tx_packet_handler, s->chan) == NULL) { ast_log(LOG_WARNING, "Unable to start T.38 termination.\n"); res = -1; goto disable_t38; } t38_set_max_datagram_size(t38state, s->t38parameters.max_ifp); if (s->t38parameters.fill_bit_removal) { t38_set_fill_bit_removal(t38state, TRUE); } if (s->t38parameters.transcoding_mmr) { t38_set_mmr_transcoding(t38state, TRUE); } if (s->t38parameters.transcoding_jbig) { t38_set_jbig_transcoding(t38state, TRUE); } /* Setup logging */ set_logging(&t38.logging); set_logging(&t30state->logging); set_logging(&t38state->logging); /* Configure terminal */ set_local_info(t30state, s); set_file(t30state, s); set_ecm(t30state, TRUE); t30_set_phase_e_handler(t30state, phase_e_handler, s); now = start = state_change = ast_tvnow(); while (!s->finished) { inf = NULL; if ((res = ast_waitfor(s->chan, 25)) < 0) { ast_debug(1, "Error waiting for a frame\n"); break; } last_frame = now; /* Watchdog */ now = ast_tvnow(); if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) { ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n"); res = -1; break; } t38_terminal_send_timeout(&t38, ast_tvdiff_us(now, last_frame) / (1000000 / 8000)); if (!res) { /* There was timeout waiting for a frame. Loop around and wait again */ continue; } /* There is a frame available. Get it */ res = 0; if (!(inf = ast_read(s->chan))) { ast_debug(1, "Channel hangup\n"); res = -1; break; } ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass.integer, inf->datalen); if (inf->frametype == AST_FRAME_MODEM && inf->subclass.integer == AST_MODEM_T38) { t38_core_rx_ifp_packet(t38state, inf->data.ptr, inf->datalen, inf->seqno); if (last_state != t30state->state) { state_change = ast_tvnow(); last_state = t30state->state; } } else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass.integer == AST_CONTROL_T38_PARAMETERS) { struct ast_control_t38_parameters *parameters = inf->data.ptr; if (parameters->request_response == AST_T38_TERMINATED) { ast_debug(1, "T38 down, finishing\n"); break; } } ast_frfree(inf); inf = NULL; } ast_debug(1, "Loop finished, res=%d\n", res); if (inf) ast_frfree(inf); t30_terminate(t30state); t38_terminal_release(&t38); disable_t38: /* if we are not the caller, it's our job to shut down the T.38 * session when the FAX transmisson is complete. */ if ((s->caller_mode == FALSE) && (ast_channel_get_t38_state(s->chan) == T38_STATE_NEGOTIATED)) { struct ast_control_t38_parameters t38_parameters = { .request_response = AST_T38_REQUEST_TERMINATE, }; if (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0) { /* wait up to five seconds for negotiation to complete */ unsigned int timeout = 5000; int ms; ast_debug(1, "Shutting down T.38 on %s\n", ast_channel_name(s->chan)); while (timeout > 0) { ms = ast_waitfor(s->chan, 1000); if (ms < 0) { ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", ast_channel_name(s->chan)); return -1; } if (!ms) { /* nothing happened */ if (timeout > 0) { timeout -= 1000; continue; } else { ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 shutdown.\n", ast_channel_name(s->chan)); break; } } if (!(inf = ast_read(s->chan))) { return -1; } if ((inf->frametype == AST_FRAME_CONTROL) && (inf->subclass.integer == AST_CONTROL_T38_PARAMETERS) && (inf->datalen == sizeof(t38_parameters))) { struct ast_control_t38_parameters *parameters = inf->data.ptr; switch (parameters->request_response) { case AST_T38_TERMINATED: ast_debug(1, "Shut down T.38 on %s\n", ast_channel_name(s->chan)); break; case AST_T38_REFUSED: ast_log(LOG_WARNING, "channel '%s' refused to disable T.38\n", ast_channel_name(s->chan)); break; default: ast_log(LOG_ERROR, "channel '%s' failed to disable T.38\n", ast_channel_name(s->chan)); break; } ast_frfree(inf); break; } ast_frfree(inf); } } } return res; }
static int extenspy_exec(struct ast_channel *chan, const char *data) { char *ptr, *exten = NULL; char *mygroup = NULL; char *recbase = NULL; int fd = 0; struct ast_flags flags; struct spy_dtmf_options user_options = { .cycle = '*', .volume = '#', .exit = '\0', }; RAII_VAR(struct ast_format *, oldwf, NULL, ao2_cleanup); int volfactor = 0; int res; char *mailbox = NULL; char *name_context = NULL; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(context); AST_APP_ARG(options); ); char *parse = ast_strdupa(data); AST_STANDARD_APP_ARGS(args, parse); if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) { exten = args.context; *ptr++ = '\0'; args.context = ptr; } if (ast_strlen_zero(args.context)) args.context = ast_strdupa(ast_channel_context(chan)); if (args.options) { char *opts[OPT_ARG_ARRAY_SIZE]; char tmp; ast_app_parse_options(spy_opts, &flags, opts, args.options); if (ast_test_flag(&flags, OPTION_GROUP)) mygroup = opts[OPT_ARG_GROUP]; if (ast_test_flag(&flags, OPTION_RECORD) && !(recbase = opts[OPT_ARG_RECORD])) recbase = "chanspy"; if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) { tmp = opts[OPT_ARG_EXIT][0]; if (strchr("0123456789*#", tmp) && tmp != '\0') { user_options.exit = tmp; } else { ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n"); } } if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) { tmp = opts[OPT_ARG_CYCLE][0]; if (strchr("0123456789*#", tmp) && tmp != '\0') { user_options.cycle = tmp; } else { ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n"); } } if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { int vol; if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4)) ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); else volfactor = vol; } if (ast_test_flag(&flags, OPTION_PRIVATE)) ast_set_flag(&flags, OPTION_WHISPER); if (ast_test_flag(&flags, OPTION_NAME)) { if (!ast_strlen_zero(opts[OPT_ARG_NAME])) { char *delimiter; if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) { mailbox = opts[OPT_ARG_NAME]; *delimiter++ = '\0'; name_context = delimiter; } else { mailbox = opts[OPT_ARG_NAME]; } } } } else { /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ ast_clear_flag(&flags, AST_FLAGS_ALL); } oldwf = ao2_bump(ast_channel_writeformat(chan)); if (ast_set_write_format(chan, ast_format_slin) < 0) { ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); return -1; } if (recbase) { char filename[PATH_MAX]; snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) { ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); fd = 0; } } res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, NULL, NULL, exten, args.context, mailbox, name_context); if (fd) close(fd); if (oldwf && ast_set_write_format(chan, oldwf) < 0) ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); return res; }
struct ast_codec *ast_format_get_codec(const struct ast_format *format) { return ao2_bump(format->codec); }
static int srv_resolve(struct ast_dns_query *query) { pthread_t thread; return ast_pthread_create_detached(&thread, NULL, srv_thread, ao2_bump(query)); }
/*! \brief Query resolution callback */ static void dns_query_recurring_resolution_callback(const struct ast_dns_query *query) { struct ast_dns_query_recurring *recurring = ast_dns_query_get_data(query); struct ast_dns_query *callback_query; /* Create a separate query to invoke the user specific callback on as the * recurring query user data may get used externally (by the unit test) * and thus changing it is problematic */ callback_query = dns_query_alloc(query->name, query->rr_type, query->rr_class, recurring->callback, recurring->user_data); if (callback_query) { /* The result is immutable at this point and can be safely provided */ callback_query->result = query->result; callback_query->callback(callback_query); callback_query->result = NULL; ao2_ref(callback_query, -1); } ao2_lock(recurring); /* So.. if something has not externally cancelled this we can reschedule based on the TTL */ if (!recurring->cancelled) { const struct ast_dns_result *result = ast_dns_query_get_result(query); int ttl = MIN(ast_dns_result_get_lowest_ttl(result), INT_MAX / 1000); if (ttl) { recurring->timer = ast_sched_add(ast_dns_get_sched(), ttl * 1000, dns_query_recurring_scheduled_callback, ao2_bump(recurring)); if (recurring->timer < 0) { /* It is impossible for this to be the last reference as the query has a reference to it */ ao2_ref(recurring, -1); } } } ao2_replace(recurring->active, NULL); ao2_unlock(recurring); }
struct stasis_app_recording *stasis_app_control_record( struct stasis_app_control *control, struct stasis_app_recording_options *options) { struct stasis_app_recording *recording; char *last_slash; errno = 0; if (options == NULL || ast_strlen_zero(options->name) || ast_strlen_zero(options->format) || options->max_silence_seconds < 0 || options->max_duration_seconds < 0) { errno = EINVAL; return NULL; } ast_debug(3, "%s: Sending record(%s.%s) command\n", stasis_app_control_get_channel_id(control), options->name, options->format); recording = ao2_alloc(sizeof(*recording), recording_dtor); if (!recording) { errno = ENOMEM; return NULL; } recording->duration.total = -1; recording->duration.energy_only = -1; ast_asprintf(&recording->absolute_name, "%s/%s", ast_config_AST_RECORDING_DIR, options->name); if (recording->absolute_name == NULL) { errno = ENOMEM; ao2_ref(recording, -1); return NULL; } if ((last_slash = strrchr(recording->absolute_name, '/'))) { *last_slash = '\0'; if (ast_safe_mkdir(ast_config_AST_RECORDING_DIR, recording->absolute_name, 0777) != 0) { /* errno set by ast_mkdir */ ao2_ref(recording, -1); return NULL; } *last_slash = '/'; } ao2_ref(options, +1); recording->options = options; recording->control = control; recording->state = STASIS_APP_RECORDING_STATE_QUEUED; if ((recording->options->if_exists == AST_RECORD_IF_EXISTS_FAIL) && (ast_fileexists(recording->absolute_name, NULL, NULL))) { ast_log(LOG_WARNING, "Recording file '%s' already exists and ifExists option is failure.\n", recording->absolute_name); errno = EEXIST; ao2_ref(recording, -1); return NULL; } { RAII_VAR(struct stasis_app_recording *, old_recording, NULL, ao2_cleanup); SCOPED_AO2LOCK(lock, recordings); old_recording = ao2_find(recordings, options->name, OBJ_KEY | OBJ_NOLOCK); if (old_recording) { ast_log(LOG_WARNING, "Recording %s already in progress\n", recording->options->name); errno = EEXIST; ao2_ref(recording, -1); return NULL; } ao2_link(recordings, recording); } stasis_app_control_register_add_rule(control, &rule_recording); stasis_app_send_command_async(control, record_file, ao2_bump(recording), recording_cleanup); return recording; }
static int cli_channelstats_print_body(void *obj, void *arg, int flags) { struct ast_sip_cli_context *context = arg; const struct ast_channel_snapshot *snapshot = obj; struct ast_channel *channel = ast_channel_get_by_name(snapshot->name); struct ast_sip_channel_pvt *cpvt = channel ? ast_channel_tech_pvt(channel) : NULL; struct ast_sip_session *session; struct ast_sip_session_media *media; struct ast_rtp_instance *rtp; struct ast_rtp_instance_stats stats; char *print_name = NULL; char *print_time = alloca(32); char codec_in_use[7]; ast_assert(context->output_buffer != NULL); if (!channel) { ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name); return -1; } ast_channel_lock(channel); session = cpvt->session; if (!session) { ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name); ast_channel_unlock(channel); ao2_cleanup(channel); return -1; } media = session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]; if (!media || !media->rtp) { ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name); ast_channel_unlock(channel); ao2_cleanup(channel); return -1; } rtp = ao2_bump(media->rtp); codec_in_use[0] = '\0'; if (ast_channel_rawreadformat(channel)) { ast_copy_string(codec_in_use, ast_format_get_name(ast_channel_rawreadformat(channel)), sizeof(codec_in_use)); } ast_channel_unlock(channel); print_name = ast_strdupa(snapshot->name); /* Skip the PJSIP/. We know what channel type it is and we need the space. */ print_name += 6; ast_format_duration_hh_mm_ss(ast_tvnow().tv_sec - snapshot->creationtime.tv_sec, print_time, 32); if (ast_rtp_instance_get_stats(rtp, &stats, AST_RTP_INSTANCE_STAT_ALL)) { ast_str_append(&context->output_buffer, 0, "%s direct media\n", snapshot->name); } else { ast_str_append(&context->output_buffer, 0, " %8.8s %-18.18s %-8.8s %-6.6s %6u%s %6u%s %3u %7.3f %6u%s %6u%s %3u %7.3f %7.3f\n", snapshot->bridgeid, print_name, print_time, codec_in_use, stats.rxcount > 100000 ? stats.rxcount / 1000 : stats.rxcount, stats.rxcount > 100000 ? "K": " ", stats.rxploss > 100000 ? stats.rxploss / 1000 : stats.rxploss, stats.rxploss > 100000 ? "K": " ", stats.rxcount ? (stats.rxploss * 100) / stats.rxcount : 0, MIN(stats.rxjitter, 999.999), stats.txcount > 100000 ? stats.txcount / 1000 : stats.txcount, stats.txcount > 100000 ? "K": " ", stats.txploss > 100000 ? stats.txploss / 1000 : stats.txploss, stats.txploss > 100000 ? "K": " ", stats.txcount ? (stats.txploss * 100) / stats.txcount : 0, MIN(stats.txjitter, 999.999), MIN(stats.normdevrtt, 999.999) ); } ao2_cleanup(rtp); ao2_cleanup(channel); return 0; }
static pj_bool_t distributor(pjsip_rx_data *rdata) { pjsip_dialog *dlg; struct distributor_dialog_data *dist = NULL; struct ast_taskprocessor *serializer = NULL; pjsip_rx_data *clone; if (!ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) { /* * Ignore everything until we are fully booted. Let the * peer retransmit messages until we are ready. */ return PJ_TRUE; } dlg = find_dialog(rdata); if (dlg) { ast_debug(3, "Searching for serializer associated with dialog %s for %s\n", dlg->obj_name, pjsip_rx_data_get_info(rdata)); dist = ao2_find(dialog_associations, dlg, OBJ_SEARCH_KEY); if (dist) { ao2_lock(dist); serializer = ao2_bump(dist->serializer); ao2_unlock(dist); if (serializer) { ast_debug(3, "Found serializer %s associated with dialog %s\n", ast_taskprocessor_name(serializer), dlg->obj_name); } } } if (serializer) { /* We have a serializer so we know where to send the message. */ } else if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG) { ast_debug(3, "No dialog serializer for %s. Using request transaction as basis.\n", pjsip_rx_data_get_info(rdata)); serializer = find_request_serializer(rdata); if (!serializer) { /* * Pick a serializer for the unmatched response. * We couldn't determine what serializer originally * sent the request or the serializer is gone. */ serializer = ast_sip_get_distributor_serializer(rdata); } } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_cancel_method) || !pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_bye_method)) { /* We have a BYE or CANCEL request without a serializer. */ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL, NULL, NULL); ao2_cleanup(dist); return PJ_TRUE; } else { if (ast_taskprocessor_alert_get()) { /* * When taskprocessors get backed up, there is a good chance that * we are being overloaded and need to defer adding new work to * the system. To defer the work we will ignore the request and * rely on the peer's transport layer to retransmit the message. * We usually work off the overload within a few seconds. The * alternative is to send back a 503 response to these requests * and be done with it. */ ast_debug(3, "Taskprocessor overload alert: Ignoring '%s'.\n", pjsip_rx_data_get_info(rdata)); ao2_cleanup(dist); return PJ_TRUE; } /* Pick a serializer for the out-of-dialog request. */ serializer = ast_sip_get_distributor_serializer(rdata); } if (pjsip_rx_data_clone(rdata, 0, &clone) != PJ_SUCCESS) { ast_taskprocessor_unreference(serializer); ao2_cleanup(dist); return PJ_TRUE; } if (dist) { ao2_lock(dist); clone->endpt_info.mod_data[endpoint_mod.id] = ao2_bump(dist->endpoint); ao2_unlock(dist); ao2_cleanup(dist); } if (ast_sip_push_task(serializer, distribute, clone)) { ao2_cleanup(clone->endpt_info.mod_data[endpoint_mod.id]); pjsip_rx_data_free_cloned(clone); } ast_taskprocessor_unreference(serializer); return PJ_TRUE; }
static int create_jb(struct ast_channel *chan, struct ast_frame *frr) { struct ast_jb *jb = ast_channel_jb(chan); struct ast_jb_conf *jbconf = &jb->conf; const struct ast_jb_impl *jbimpl = jb->impl; void *jbobj; long now; char logfile_pathname[20 + AST_JB_IMPL_NAME_SIZE + 2*AST_CHANNEL_NAME + 1]; char name1[AST_CHANNEL_NAME], name2[AST_CHANNEL_NAME], *tmp; int res; jbobj = jb->jbobj = jbimpl->create(jbconf); if (!jbobj) { ast_log(LOG_WARNING, "Failed to create jitterbuffer on channel '%s'\n", ast_channel_name(chan)); return -1; } now = get_now(jb, NULL); res = jbimpl->put_first(jbobj, frr, now); /* The result of putting the first frame should not differ from OK. However, its possible some implementations (i.e. adaptive's when resynch_threshold is specified) to drop it. */ if (res != AST_JB_IMPL_OK) { ast_log(LOG_WARNING, "Failed to put first frame in the jitterbuffer on channel '%s'\n", ast_channel_name(chan)); /* jbimpl->destroy(jbobj); return -1; */ } /* Init next */ jb->next = jbimpl->next(jbobj); /* Init last format for a first time. */ jb->last_format = ao2_bump(frr->subclass.format); /* Create a frame log file */ if (ast_test_flag(jbconf, AST_JB_LOG)) { RAII_VAR(struct ast_channel *, bridged, ast_channel_bridge_peer(chan), ast_channel_cleanup); char safe_logfile[30] = "/tmp/logfile-XXXXXX"; int safe_fd; snprintf(name2, sizeof(name2), "%s", ast_channel_name(chan)); while ((tmp = strchr(name2, '/'))) { *tmp = '#'; } /* We should always have bridged chan if a jitterbuffer is in use */ ast_assert(bridged != NULL); snprintf(name1, sizeof(name1), "%s", ast_channel_name(bridged)); while ((tmp = strchr(name1, '/'))) { *tmp = '#'; } snprintf(logfile_pathname, sizeof(logfile_pathname), "/tmp/ast_%s_jb_%s--%s.log", jbimpl->name, name1, name2); unlink(logfile_pathname); safe_fd = mkstemp(safe_logfile); if (safe_fd < 0 || link(safe_logfile, logfile_pathname) || unlink(safe_logfile) || !(jb->logfile = fdopen(safe_fd, "w+b"))) { ast_log(LOG_ERROR, "Failed to create frame log file with pathname '%s': %s\n", logfile_pathname, strerror(errno)); jb->logfile = NULL; if (safe_fd > -1) { close(safe_fd); } } if (res == AST_JB_IMPL_OK) { jb_framelog("JB_PUT_FIRST {now=%ld}: Queued frame with ts=%ld and len=%ld\n", now, frr->ts, frr->len); } else { jb_framelog("JB_PUT_FIRST {now=%ld}: Dropped frame with ts=%ld and len=%ld\n", now, frr->ts, frr->len); } } ast_verb(3, "%s jitterbuffer created on channel %s\n", jbimpl->name, ast_channel_name(chan)); /* Free the frame if it has not been queued in the jb */ if (res != AST_JB_IMPL_OK) { ast_frfree(frr); } return 0; }