static void jb_get_and_deliver(struct ast_channel *chan) { struct ast_jb *jb = ast_channel_jb(chan); const struct ast_jb_impl *jbimpl = jb->impl; void *jbobj = jb->jbobj; struct ast_frame *f, finterp = { .frametype = AST_FRAME_VOICE, }; long now; int interpolation_len, res; now = get_now(jb, NULL); jb->next = jbimpl->next(jbobj); if (now < jb->next) { jb_framelog("\tJB_GET {now=%ld}: now < next=%ld\n", now, jb->next); return; } while (now >= jb->next) { interpolation_len = ast_format_get_default_ms(jb->last_format); res = jbimpl->get(jbobj, &f, now, interpolation_len); switch (res) { case AST_JB_IMPL_OK: /* deliver the frame */ ast_write(chan, f); case AST_JB_IMPL_DROP: jb_framelog("\tJB_GET {now=%ld}: %s frame with ts=%ld and len=%ld\n", now, jb_get_actions[res], f->ts, f->len); ao2_replace(jb->last_format, f->subclass.format); ast_frfree(f); break; case AST_JB_IMPL_INTERP: /* interpolate a frame */ f = &finterp; f->subclass.format = jb->last_format; f->samples = interpolation_len * 8; f->src = "JB interpolation"; f->delivery = ast_tvadd(jb->timebase, ast_samp2tv(jb->next, 1000)); f->offset = AST_FRIENDLY_OFFSET; /* deliver the interpolated frame */ ast_write(chan, f); jb_framelog("\tJB_GET {now=%ld}: Interpolated frame with len=%d\n", now, interpolation_len); break; case AST_JB_IMPL_NOFRAME: ast_log(LOG_WARNING, "AST_JB_IMPL_NOFRAME is returned from the %s jb when now=%ld >= next=%ld, jbnext=%ld!\n", jbimpl->name, now, jb->next, jbimpl->next(jbobj)); jb_framelog("\tJB_GET {now=%ld}: No frame for now!?\n", now); return; default: ast_log(LOG_ERROR, "This should never happen!\n"); ast_assert("JB type unknown" == NULL); break; } jb->next = jbimpl->next(jbobj); } }
static void apply_acls(pjsip_rx_data *rdata) { struct ast_sip_endpoint *endpoint; /* Is the endpoint allowed with the source or contact address? */ endpoint = rdata->endpt_info.mod_data[endpoint_mod.id]; if (endpoint != artificial_endpoint && (apply_endpoint_acl(rdata, endpoint) || apply_endpoint_contact_acl(rdata, endpoint))) { ast_debug(1, "Endpoint '%s' not allowed by ACL\n", ast_sorcery_object_get_id(endpoint)); /* Replace the rdata endpoint with the artificial endpoint. */ ao2_replace(rdata->endpt_info.mod_data[endpoint_mod.id], artificial_endpoint); } }
int ast_dns_resolve_recurring_cancel(struct ast_dns_query_recurring *recurring) { int res = 0; ao2_lock(recurring); recurring->cancelled = 1; AST_SCHED_DEL_UNREF(ast_dns_get_sched(), recurring->timer, ao2_ref(recurring, -1)); if (recurring->active) { res = ast_dns_resolve_cancel(recurring->active); ao2_replace(recurring->active, NULL); } ao2_unlock(recurring); return res; }
void app_update(struct stasis_app *app, stasis_app_cb handler, void *data) { ao2_lock(app); if (app->handler && app->data) { struct ast_json *msg; ast_verb(1, "Replacing Stasis app '%s'\n", app->name); msg = ast_json_pack("{s: s, s: s}", "type", "ApplicationReplaced", "application", app->name); if (msg) { app_send(app, msg); ast_json_unref(msg); } } else { ast_verb(1, "Activating Stasis app '%s'\n", app->name); } app->handler = handler; ao2_replace(app->data, data); ao2_unlock(app); }
/*! \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); }
static void set_cached_format(const char *name, struct ast_format *format) { if (!strcmp(name, "g723")) { ao2_replace(ast_format_g723, format); } else if (!strcmp(name, "ulaw")) { ao2_replace(ast_format_ulaw, format); } else if (!strcmp(name, "alaw")) { ao2_replace(ast_format_alaw, format); } else if (!strcmp(name, "gsm")) { ao2_replace(ast_format_gsm, format); } else if (!strcmp(name, "g726")) { ao2_replace(ast_format_g726, format); } else if (!strcmp(name, "g726aal2")) { ao2_replace(ast_format_g726_aal2, format); } else if (!strcmp(name, "adpcm")) { ao2_replace(ast_format_adpcm, format); } else if (!strcmp(name, "slin")) { ao2_replace(ast_format_slin, format); } else if (!strcmp(name, "slin12")) { ao2_replace(ast_format_slin12, format); } else if (!strcmp(name, "slin16")) { ao2_replace(ast_format_slin16, format); } else if (!strcmp(name, "slin24")) { ao2_replace(ast_format_slin24, format); } else if (!strcmp(name, "slin32")) { ao2_replace(ast_format_slin32, format); } else if (!strcmp(name, "slin44")) { ao2_replace(ast_format_slin44, format); } else if (!strcmp(name, "slin48")) { ao2_replace(ast_format_slin48, format); } else if (!strcmp(name, "slin96")) { ao2_replace(ast_format_slin96, format); } else if (!strcmp(name, "slin192")) { ao2_replace(ast_format_slin192, format); } else if (!strcmp(name, "lpc10")) { ao2_replace(ast_format_lpc10, format); } else if (!strcmp(name, "g729")) { ao2_replace(ast_format_g729, format); } else if (!strcmp(name, "speex")) { ao2_replace(ast_format_speex, format); } else if (!strcmp(name, "speex16")) { ao2_replace(ast_format_speex16, format); } else if (!strcmp(name, "speex32")) { ao2_replace(ast_format_speex32, format); } else if (!strcmp(name, "ilbc")) { ao2_replace(ast_format_ilbc, format); } else if (!strcmp(name, "g722")) { ao2_replace(ast_format_g722, format); } else if (!strcmp(name, "siren7")) { ao2_replace(ast_format_siren7, format); } else if (!strcmp(name, "siren14")) { ao2_replace(ast_format_siren14, format); } else if (!strcmp(name, "testlaw")) { ao2_replace(ast_format_testlaw, format); } else if (!strcmp(name, "g719")) { ao2_replace(ast_format_g719, format); } else if (!strcmp(name, "opus")) { ao2_replace(ast_format_opus, format); } else if (!strcmp(name, "jpeg")) { ao2_replace(ast_format_jpeg, format); } else if (!strcmp(name, "png")) { ao2_replace(ast_format_png, format); } else if (!strcmp(name, "h261")) { ao2_replace(ast_format_h261, format); } else if (!strcmp(name, "h263")) { ao2_replace(ast_format_h263, format); } else if (!strcmp(name, "h263p")) { ao2_replace(ast_format_h263p, format); } else if (!strcmp(name, "h264")) { ao2_replace(ast_format_h264, format); } else if (!strcmp(name, "mpeg4")) { ao2_replace(ast_format_mp4, format); } else if (!strcmp(name, "vp8")) { ao2_replace(ast_format_vp8, format); } else if (!strcmp(name, "red")) { ao2_replace(ast_format_t140_red, format); } else if (!strcmp(name, "t140")) { ao2_replace(ast_format_t140, format); } else if (!strcmp(name, "none")) { ao2_replace(ast_format_none, format); } }
/*! \brief Function called when the process is shutting down */ static void format_cache_shutdown(void) { ao2_cleanup(formats); formats = NULL; ao2_replace(ast_format_g723, NULL); ao2_replace(ast_format_ulaw, NULL); ao2_replace(ast_format_alaw, NULL); ao2_replace(ast_format_gsm, NULL); ao2_replace(ast_format_g726, NULL); ao2_replace(ast_format_g726_aal2, NULL); ao2_replace(ast_format_adpcm, NULL); ao2_replace(ast_format_slin, NULL); ao2_replace(ast_format_slin12, NULL); ao2_replace(ast_format_slin16, NULL); ao2_replace(ast_format_slin24, NULL); ao2_replace(ast_format_slin32, NULL); ao2_replace(ast_format_slin44, NULL); ao2_replace(ast_format_slin48, NULL); ao2_replace(ast_format_slin96, NULL); ao2_replace(ast_format_slin192, NULL); ao2_replace(ast_format_lpc10, NULL); ao2_replace(ast_format_g729, NULL); ao2_replace(ast_format_speex, NULL); ao2_replace(ast_format_speex16, NULL); ao2_replace(ast_format_speex32, NULL); ao2_replace(ast_format_ilbc, NULL); ao2_replace(ast_format_g722, NULL); ao2_replace(ast_format_siren7, NULL); ao2_replace(ast_format_siren14, NULL); ao2_replace(ast_format_testlaw, NULL); ao2_replace(ast_format_g719, NULL); ao2_replace(ast_format_opus, NULL); ao2_replace(ast_format_jpeg, NULL); ao2_replace(ast_format_png, NULL); ao2_replace(ast_format_h261, NULL); ao2_replace(ast_format_h263, NULL); ao2_replace(ast_format_h263p, NULL); ao2_replace(ast_format_h264, NULL); ao2_replace(ast_format_mp4, NULL); ao2_replace(ast_format_vp8, NULL); ao2_replace(ast_format_t140_red, NULL); ao2_replace(ast_format_t140, NULL); ao2_replace(ast_format_none, NULL); }
/*! \brief Apply handler for transports */ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) { struct ast_sip_transport *transport = obj; const char *transport_id = ast_sorcery_object_get_id(obj); RAII_VAR(struct ao2_container *, states, transport_states, states_cleanup); RAII_VAR(struct internal_state *, temp_state, NULL, ao2_cleanup); RAII_VAR(struct internal_state *, perm_state, NULL, ao2_cleanup); RAII_VAR(struct ast_variable *, changes, NULL, ast_variables_destroy); pj_status_t res = -1; int i; #define BIND_TRIES 3 #define BIND_DELAY_US 100000 if (!states) { return -1; } /* * transport_apply gets called for EVERY retrieval of a transport when using realtime. * We need to prevent multiple threads from trying to mess with underlying transports * at the same time. The container is the only thing we have to lock on. */ ao2_wrlock(states); temp_state = internal_state_alloc(transport); if (!temp_state) { ast_log(LOG_ERROR, "Transport '%s' failed to allocate memory\n", transport_id); return -1; } perm_state = find_internal_state_by_transport(transport); if (perm_state) { ast_sorcery_diff(sorcery, perm_state->transport, transport, &changes); if (!changes && !has_state_changed(perm_state->state, temp_state->state)) { /* In case someone is using the deprecated fields, reset them */ transport->state = perm_state->state; copy_state_to_transport(transport); ao2_replace(perm_state->transport, transport); return 0; } if (!transport->allow_reload) { if (!perm_state->change_detected) { perm_state->change_detected = 1; ast_log(LOG_WARNING, "Transport '%s' is not reloadable, maintaining previous values\n", transport_id); } /* In case someone is using the deprecated fields, reset them */ transport->state = perm_state->state; copy_state_to_transport(transport); ao2_replace(perm_state->transport, transport); return 0; } } if (temp_state->state->host.addr.sa_family != PJ_AF_INET && temp_state->state->host.addr.sa_family != PJ_AF_INET6) { ast_log(LOG_ERROR, "Transport '%s' could not be started as binding not specified\n", transport_id); return -1; } /* Set default port if not present */ if (!pj_sockaddr_get_port(&temp_state->state->host)) { pj_sockaddr_set_port(&temp_state->state->host, (transport->type == AST_TRANSPORT_TLS) ? 5061 : 5060); } /* Now that we know what address family we can set up a dnsmgr refresh for the external media address if present */ if (!ast_strlen_zero(transport->external_signaling_address)) { if (temp_state->state->host.addr.sa_family == pj_AF_INET()) { temp_state->state->external_address.ss.ss_family = AF_INET; } else if (temp_state->state->host.addr.sa_family == pj_AF_INET6()) { temp_state->state->external_address.ss.ss_family = AF_INET6; } else { ast_log(LOG_ERROR, "Unknown address family for transport '%s', could not get external signaling address\n", transport_id); return -1; } if (ast_dnsmgr_lookup(transport->external_signaling_address, &temp_state->state->external_address, &temp_state->state->external_address_refresher, NULL) < 0) { ast_log(LOG_ERROR, "Could not create dnsmgr for external signaling address on '%s'\n", transport_id); return -1; } } if (transport->type == AST_TRANSPORT_UDP) { for (i = 0; i < BIND_TRIES && res != PJ_SUCCESS; i++) { if (perm_state && perm_state->state && perm_state->state->transport) { pjsip_udp_transport_pause(perm_state->state->transport, PJSIP_UDP_TRANSPORT_DESTROY_SOCKET); usleep(BIND_DELAY_US); } if (temp_state->state->host.addr.sa_family == pj_AF_INET()) { res = pjsip_udp_transport_start(ast_sip_get_pjsip_endpoint(), &temp_state->state->host.ipv4, NULL, transport->async_operations, &temp_state->state->transport); } else if (temp_state->state->host.addr.sa_family == pj_AF_INET6()) { res = pjsip_udp_transport_start6(ast_sip_get_pjsip_endpoint(), &temp_state->state->host.ipv6, NULL, transport->async_operations, &temp_state->state->transport); } } if (res == PJ_SUCCESS && (transport->tos || transport->cos)) { pj_sock_t sock; pj_qos_params qos_params; sock = pjsip_udp_transport_get_socket(temp_state->state->transport); pj_sock_get_qos_params(sock, &qos_params); set_qos(transport, &qos_params); pj_sock_set_qos_params(sock, &qos_params); } } else if (transport->type == AST_TRANSPORT_TCP) { pjsip_tcp_transport_cfg cfg; pjsip_tcp_transport_cfg_default(&cfg, temp_state->state->host.addr.sa_family); cfg.bind_addr = temp_state->state->host; cfg.async_cnt = transport->async_operations; set_qos(transport, &cfg.qos_params); for (i = 0; i < BIND_TRIES && res != PJ_SUCCESS; i++) { if (perm_state && perm_state->state && perm_state->state->factory && perm_state->state->factory->destroy) { perm_state->state->factory->destroy(perm_state->state->factory); usleep(BIND_DELAY_US); } res = pjsip_tcp_transport_start3(ast_sip_get_pjsip_endpoint(), &cfg, &temp_state->state->factory); } } else if (transport->type == AST_TRANSPORT_TLS) { if (transport->async_operations > 1 && ast_compare_versions(pj_get_version(), "2.5.0") < 0) { ast_log(LOG_ERROR, "Transport: %s: When protocol=tls and pjproject version < 2.5.0, async_operations can't be > 1\n", ast_sorcery_object_get_id(obj)); return -1; } temp_state->state->tls.password = pj_str((char*)transport->password); set_qos(transport, &temp_state->state->tls.qos_params); for (i = 0; i < BIND_TRIES && res != PJ_SUCCESS; i++) { if (perm_state && perm_state->state && perm_state->state->factory && perm_state->state->factory->destroy) { perm_state->state->factory->destroy(perm_state->state->factory); usleep(BIND_DELAY_US); } res = pjsip_tls_transport_start2(ast_sip_get_pjsip_endpoint(), &temp_state->state->tls, &temp_state->state->host, NULL, transport->async_operations, &temp_state->state->factory); } } else if ((transport->type == AST_TRANSPORT_WS) || (transport->type == AST_TRANSPORT_WSS)) { if (transport->cos || transport->tos) { ast_log(LOG_WARNING, "TOS and COS values ignored for websocket transport\n"); } res = PJ_SUCCESS; } if (res != PJ_SUCCESS) { char msg[PJ_ERR_MSG_SIZE]; pj_strerror(res, msg, sizeof(msg)); ast_log(LOG_ERROR, "Transport '%s' could not be started: %s\n", ast_sorcery_object_get_id(obj), msg); return -1; } copy_state_to_transport(transport); if (perm_state) { ao2_unlink_flags(states, perm_state, OBJ_NOLOCK); } ao2_link_flags(states, temp_state, OBJ_NOLOCK); return 0; }
static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_frame *frame, enum ast_framehook_event event, void *data) { struct jb_framedata *framedata = data; struct timeval now_tv; unsigned long now; int putframe = 0; /* signifies if audio frame was placed into the buffer or not */ switch (event) { case AST_FRAMEHOOK_EVENT_READ: break; case AST_FRAMEHOOK_EVENT_ATTACHED: case AST_FRAMEHOOK_EVENT_DETACHED: case AST_FRAMEHOOK_EVENT_WRITE: return frame; } if (ast_channel_fdno(chan) == AST_JITTERBUFFER_FD && framedata->timer) { if (ast_timer_ack(framedata->timer, 1) < 0) { ast_log(LOG_ERROR, "Failed to acknowledge timer in jitter buffer\n"); return frame; } } if (!frame) { return frame; } now_tv = ast_tvnow(); now = ast_tvdiff_ms(now_tv, framedata->start_tv); if (frame->frametype == AST_FRAME_VOICE) { int res; struct ast_frame *jbframe; if (!ast_test_flag(frame, AST_FRFLAG_HAS_TIMING_INFO) || frame->len < 2 || frame->ts < 0) { /* only frames with timing info can enter the jitterbuffer */ return frame; } jbframe = ast_frisolate(frame); ao2_replace(framedata->last_format, frame->subclass.format); if (frame->len && (frame->len != framedata->timer_interval)) { framedata->timer_interval = frame->len; ast_timer_set_rate(framedata->timer, 1000 / framedata->timer_interval); } if (!framedata->first) { framedata->first = 1; res = framedata->jb_impl->put_first(framedata->jb_obj, jbframe, now); } else { res = framedata->jb_impl->put(framedata->jb_obj, jbframe, now); } if (res == AST_JB_IMPL_OK) { if (jbframe != frame) { ast_frfree(frame); } frame = &ast_null_frame; } else if (jbframe != frame) { ast_frfree(jbframe); } putframe = 1; } if (frame->frametype == AST_FRAME_NULL) { int res; long next = framedata->jb_impl->next(framedata->jb_obj); /* If now is earlier than the next expected output frame * from the jitterbuffer we may choose to pass on retrieving * a frame during this read iteration. The only exception * to this rule is when an audio frame is placed into the buffer * and the time for the next frame to come out of the buffer is * at least within the timer_interval of the next output frame. By * doing this we are able to feed off the timing of the input frames * and only rely on our jitterbuffer timer when frames are dropped. * During testing, this hybrid form of timing gave more reliable results. */ if (now < next) { long int diff = next - now; if (!putframe) { return frame; } else if (diff >= framedata->timer_interval) { return frame; } } ast_frfree(frame); frame = &ast_null_frame; res = framedata->jb_impl->get(framedata->jb_obj, &frame, now, framedata->timer_interval); switch (res) { case AST_JB_IMPL_OK: /* got it, and pass it through */ break; case AST_JB_IMPL_DROP: ast_frfree(frame); frame = &ast_null_frame; break; case AST_JB_IMPL_INTERP: if (framedata->last_format) { struct ast_frame tmp = { 0, }; tmp.frametype = AST_FRAME_VOICE; tmp.subclass.format = framedata->last_format; /* example: 8000hz / (1000 / 20ms) = 160 samples */ tmp.samples = ast_format_get_sample_rate(framedata->last_format) / (1000 / framedata->timer_interval); tmp.delivery = ast_tvadd(framedata->start_tv, ast_samp2tv(next, 1000)); tmp.offset = AST_FRIENDLY_OFFSET; tmp.src = "func_jitterbuffer interpolation"; ast_frfree(frame); frame = ast_frdup(&tmp); break; } /* else fall through */ case AST_JB_IMPL_NOFRAME: ast_frfree(frame); frame = &ast_null_frame; break; } } if (frame->frametype == AST_FRAME_CONTROL) { switch(frame->subclass.integer) { case AST_CONTROL_HOLD: case AST_CONTROL_UNHOLD: case AST_CONTROL_T38_PARAMETERS: case AST_CONTROL_SRCUPDATE: case AST_CONTROL_SRCCHANGE: framedata->jb_impl->force_resync(framedata->jb_obj); break; default: break; } } return frame; }