Example #1
0
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);
	}
}
Example #2
0
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);
	}
}
Example #3
0
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;
}
Example #4
0
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);
}
Example #5
0
/*! \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);
}
Example #6
0
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);
	}
}
Example #7
0
/*! \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);
}
Example #8
0
/*! \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;
}
Example #9
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;
}