Esempio n. 1
0
/* set defaults */
static int jb_framedata_init(struct jb_framedata *framedata, struct ast_jb_conf *jb_conf)
{
	int jb_impl_type = DEFAULT_TYPE;
	/* Initialize defaults */
	framedata->timer_fd = -1;
	memcpy(&framedata->jb_conf, jb_conf, sizeof(*jb_conf));

	/* Figure out implementation type from the configuration implementation string */
	if (!ast_strlen_zero(jb_conf->impl)) {
		if (!strcasecmp(jb_conf->impl, "fixed")) {
			jb_impl_type = AST_JB_FIXED;
		} else if (!strcasecmp(jb_conf->impl, "adaptive")) {
			jb_impl_type = AST_JB_ADAPTIVE;
		} else {
			ast_log(LOG_WARNING, "Unknown Jitterbuffer type %s. Failed to create jitterbuffer.\n", jb_conf->impl);
			return -1;
		}
	}

	if (!(framedata->jb_impl = ast_jb_get_impl(jb_impl_type))) {
		return -1;
	}

	if (!(framedata->timer = ast_timer_open())) {
		return -1;
	}

	framedata->timer_fd = ast_timer_fd(framedata->timer);
	framedata->timer_interval = DEFAULT_TIMER_INTERVAL;
	ast_timer_set_rate(framedata->timer, 1000 / framedata->timer_interval);
	framedata->start_tv = ast_tvnow();

	framedata->jb_obj = framedata->jb_impl->create(&framedata->jb_conf);
	return 0;
}
Esempio n. 2
0
static int at_response_orig (pvt_t* pvt, char* str, attribute_unused size_t len)
{
	int call_index = 1;
	int call_type  = 0;

	channel_queue_control (pvt, AST_CONTROL_PROGRESS);

	if (at_send_ddsetex (pvt) || at_fifo_queue_add (pvt, CMD_AT_DDSETEX, RES_OK))
	{
		ast_log (LOG_ERROR, "[%s] Error sending AT^DDSETEX\n", pvt->id);
		return -1;
	}

	if (pvt->a_timer)
	{
		ast_timer_set_rate (pvt->a_timer, 50);
	}

	/*
	 * parse ORIG info in the following format:
	 * ^ORIG:<call_index>,<call_type>
	 */

	if (!sscanf (str, "^ORIG:%d,%d", &call_index, &call_type))
	{
		ast_log (LOG_ERROR, "[%s] Error parsing ORIG event '%s'\n", pvt->id, str);
	}

	ast_debug (1, "[%s] Received call_index: %d\n", pvt->id, call_index);
	ast_debug (1, "[%s] Received call_type:  %d\n", pvt->id, call_type);

	return 0;
}
/* set defaults */
static int jb_framedata_init(struct jb_framedata *framedata, const char *data, const char *value)
{
	int jb_impl_type = DEFAULT_TYPE;

	/* Initialize defaults */
	framedata->timer_fd = -1;
	jb_conf_default(&framedata->jb_conf);
	if (!(framedata->jb_impl = ast_jb_get_impl(jb_impl_type))) {
		return -1;
	}
	if (!(framedata->timer = ast_timer_open())) {
		return -1;
	}
	framedata->timer_fd = ast_timer_fd(framedata->timer);
	framedata->timer_interval = DEFAULT_TIMER_INTERVAL;
	ast_timer_set_rate(framedata->timer, 1000 / framedata->timer_interval);
	framedata->start_tv = ast_tvnow();



	/* Now check user options to see if any of the defaults need to change. */
	if (!ast_strlen_zero(data)) {
		if (!strcasecmp(data, "fixed")) {
			jb_impl_type = AST_JB_FIXED;
		} else if (!strcasecmp(data, "adaptive")) {
			jb_impl_type = AST_JB_ADAPTIVE;
		} else {
			ast_log(LOG_WARNING, "Unknown Jitterbuffer type %s. Failed to create jitterbuffer.\n", data);
			return -1;
		}
		ast_copy_string(framedata->jb_conf.impl, data, sizeof(framedata->jb_conf.impl));
	}

	if (!ast_strlen_zero(value) && strcasecmp(value, "default")) {
		char *parse = ast_strdupa(value);
		int res = 0;
		AST_DECLARE_APP_ARGS(args,
			AST_APP_ARG(max_size);
			AST_APP_ARG(resync_threshold);
			AST_APP_ARG(target_extra);
		);
Esempio n. 4
0
static inline int at_response_ok (pvt_t* pvt)
{
	at_queue_t* e;

	if ((e = at_fifo_queue_head (pvt)) && (e->res == RES_OK || e->res == RES_CMGR))
	{
		switch (e->cmd)
		{
			/* initilization stuff */
			case CMD_AT_Z:
				if (at_send_ate0 (pvt) || at_fifo_queue_add (pvt, CMD_AT_E, RES_OK))
				{
					ast_log (LOG_ERROR, "[%s] Error disabling echo\n", pvt->id);
					goto e_return;
				}
				break;

			case CMD_AT_E:
				if (!pvt->initialized)
				{
					if (at_send_curc (pvt) || at_fifo_queue_add (pvt, CMD_AT_CURC, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error setting service messages\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CURC:
				if (!pvt->initialized)
				{
					if (pvt->u2diag != -1)
					{
						if (at_send_u2diag (pvt, pvt->u2diag) || at_fifo_queue_add (pvt, CMD_AT_U2DIAG, RES_OK))
						{
							ast_log (LOG_ERROR, "[%s] Error setting U2DIAG\n", pvt->id);
							goto e_return;
						}
					}
					else
					{
						if (at_send_cgmi (pvt) || at_fifo_queue_add (pvt, CMD_AT_CGMI, RES_OK))
						{
							ast_log (LOG_ERROR, "[%s] Error asking datacard for manufacturer info\n", pvt->id);
							goto e_return;
						}
					}
				}
				break;

			case CMD_AT_U2DIAG:
				if (!pvt->initialized)
				{
					if (at_send_cgmi (pvt) || at_fifo_queue_add (pvt, CMD_AT_CGMI, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error asking datacard for manufacturer info\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CGMI:
				if (!pvt->initialized)
				{
					if (at_send_cgmm (pvt) || at_fifo_queue_add (pvt, CMD_AT_CGMM, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error asking datacard for model info\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CGMM:
				if (!pvt->initialized)
				{
					if (at_send_cgmr (pvt) || at_fifo_queue_add (pvt, CMD_AT_CGMR, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error asking datacard for firmware info\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CGMR:
				if (!pvt->initialized)
				{
					if (at_send_cmee (pvt, 0) || at_fifo_queue_add (pvt, CMD_AT_CMEE, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error setting error verbosity level\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CMEE:
				if (!pvt->initialized)
				{
					if (at_send_cgsn (pvt) || at_fifo_queue_add (pvt, CMD_AT_CGSN, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error asking datacard for IMEI number\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CGSN:
				if (!pvt->initialized)
				{
					if (at_send_cimi (pvt) || at_fifo_queue_add (pvt, CMD_AT_CIMI, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error asking datacard for IMSI number\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CIMI:
				if (!pvt->initialized)
				{
					if (at_send_cpin_test (pvt) || at_fifo_queue_add (pvt, CMD_AT_CPIN, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error asking datacard for PIN state\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CPIN:
				if (!pvt->initialized)
				{
					if (at_send_cops_init (pvt, 0, 0) || at_fifo_queue_add (pvt, CMD_AT_COPS_INIT, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error setting operator select parameters\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_COPS_INIT:
				ast_debug (1, "[%s] Operator select parameters set\n", pvt->id);

				if (!pvt->initialized)
				{
					if (at_send_creg_init (pvt, 2) || at_fifo_queue_add (pvt, CMD_AT_CREG_INIT, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error enabeling registration info\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CREG_INIT:
				ast_debug (1, "[%s] registration info enabled\n", pvt->id);

				if (!pvt->initialized)
				{
					if (at_send_creg (pvt) || at_fifo_queue_add (pvt, CMD_AT_CREG, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error sending registration query\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CREG:
				ast_debug (1, "[%s] registration query sent\n", pvt->id);

				if (!pvt->initialized)
				{
					if (at_send_cnum (pvt) || at_fifo_queue_add (pvt, CMD_AT_CNUM, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error checking subscriber phone number\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CNUM:
				ast_debug (1, "[%s] Subscriber phone number query successed\n", pvt->id);

				if (!pvt->initialized)
				{
					if (at_send_cvoice_test (pvt) || at_fifo_queue_add (pvt, CMD_AT_CVOICE, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error checking voice capabilities\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CVOICE:
				ast_debug (1, "[%s] Datacard has voice support\n", pvt->id);

				pvt->has_voice = 1;

				if (!pvt->initialized)
				{
					if (at_send_clip (pvt, 1) || at_fifo_queue_add (pvt, CMD_AT_CLIP, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error enabling calling line notification\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CLIP:
				ast_debug (1, "[%s] Calling line indication enabled\n", pvt->id);

				if (!pvt->initialized)
				{
					if (at_send_cssn (pvt, 1, 1) || at_fifo_queue_add (pvt, CMD_AT_CSSN, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error activating Supplementary Service Notification\n", pvt->id);
						goto e_return;
					}
				}

				break;

			case CMD_AT_CSSN:
				ast_debug (1, "[%s] Supplementary Service Notification enabled successful\n", pvt->id);

				if (!pvt->initialized)
				{
					/* set the SMS operating mode to text mode */
					if (at_send_cmgf (pvt, 1) || at_fifo_queue_add (pvt, CMD_AT_CMGF, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error setting CMGF\n", pvt->id);
						goto e_return;
					}
				}

				break;

			case CMD_AT_CMGF:
				ast_debug (1, "[%s] SMS text mode enabled\n", pvt->id);

				if (!pvt->initialized)
				{
					/* set text encoding to UCS-2 */
					if (at_send_cscs (pvt, "UCS2") || at_fifo_queue_add (pvt, CMD_AT_CSCS, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error setting CSCS (text encoding)\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CSCS:
				ast_debug (1, "[%s] UCS-2 text encoding enabled\n", pvt->id);

				pvt->use_ucs2_encoding = 1;

				if (!pvt->initialized)
				{
					/* set SMS storage location */
					if (at_send_cpms (pvt) || at_fifo_queue_add (pvt, CMD_AT_CPMS, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error setting CPMS\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CPMS:
				ast_debug (1, "[%s] SMS storage location is established\n", pvt->id);

				if (!pvt->initialized)
				{
					/* turn on SMS new message indication */
					if (at_send_cnmi (pvt) || at_fifo_queue_add (pvt, CMD_AT_CNMI, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error sending CNMI\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CNMI:
				ast_debug (1, "[%s] SMS new message indication enabled\n", pvt->id);
				ast_debug (1, "[%s] Datacard has sms support\n", pvt->id);

				pvt->has_sms = 1;

				if (!pvt->initialized)
				{
					if (at_send_csq (pvt) || at_fifo_queue_add (pvt, CMD_AT_CSQ, RES_OK))
					{
						ast_log (LOG_ERROR, "[%s] Error querying signal strength\n", pvt->id);
						goto e_return;
					}
				}
				break;

			case CMD_AT_CSQ:
				ast_debug (1, "[%s] Got signal strength result\n", pvt->id);

				if (!pvt->initialized)
				{
					ast_verb (3, "Datacard %s initialized and ready\n", pvt->id);

					pvt->timeout = 7000;
					pvt->initialized = 1;

					if (pvt->has_sms && pvt->auto_delete_sms)
					{
						if (at_send_cmgd (pvt, 1, 4) || at_fifo_queue_add (pvt, CMD_AT_CMGD, RES_OK))
						{
							ast_log (LOG_ERROR, "[%s] Error delete SMS messages\n", pvt->id);
							goto e_return;
						}
					}
				}
				break;

			/* end initilization stuff */

			case CMD_AT_A:
				ast_debug (1, "[%s] Answer sent successfully\n", pvt->id);

				if (at_send_ddsetex (pvt) || at_fifo_queue_add (pvt, CMD_AT_DDSETEX, RES_OK))
				{
					ast_log (LOG_ERROR, "[%s] Error sending AT^DDSETEX\n", pvt->id);
					goto e_return;
				}

				if (pvt->a_timer)
				{
					ast_timer_set_rate (pvt->a_timer, 50);
				}

				break;

			case CMD_AT_CLIR:
				ast_debug (1, "[%s] CLIR sent successfully\n", pvt->id);

				if (e->ptype != 0 || at_send_atd (pvt, e->param.data) || at_fifo_queue_add (pvt, CMD_AT_D, RES_OK))
				{
					ast_log (LOG_ERROR, "[%s] Error sending ATD command\n", pvt->id);
					goto e_return;
				}
				break;

			case CMD_AT_D:
				ast_debug (1, "[%s] Dial sent successfully\n", pvt->id);
				break;

			case CMD_AT_DDSETEX:
				ast_debug (1, "[%s] AT^DDSETEX sent successfully\n", pvt->id);
				break;

			case CMD_AT_CHUP:
				ast_debug (1, "[%s] Successful hangup\n", pvt->id);
				break;

			case CMD_AT_CMGS:
				ast_debug (1, "[%s] Successfully sent sms message\n", pvt->id);
				pvt->outgoing_sms = 0;
				break;

			case CMD_AT_DTMF:
				ast_debug (1, "[%s] DTMF sent successfully\n", pvt->id);
				break;

			case CMD_AT_CUSD:
				ast_debug (1, "[%s] CUSD code sent successfully\n", pvt->id);
				break;

			case CMD_AT_COPS:
				ast_debug (1, "[%s] Provider query successfully\n", pvt->id);
				break;

			case CMD_AT_CMGR:
				ast_debug (1, "[%s] SMS message see later\n", pvt->id);
				break;

			case CMD_AT_CMGD:
				ast_debug (1, "[%s] SMS message deleted successfully\n", pvt->id);
				break;
			
			case CMD_AT_CCWA:
				ast_log (LOG_NOTICE, "[%s] Call-Waiting disabled.\n", pvt->id);
				break;
			
			case CMD_AT_CFUN:
				ast_debug (1, "[%s] CFUN sent successfully\n", pvt->id);
				break;

			case CMD_AT_CLVL:
				ast_debug (1, "[%s] Audio level is set\n", pvt->id);
				break;

			default:
				ast_log (LOG_ERROR, "[%s] Received 'OK' for unhandled command '%s'\n", pvt->id, at_cmd2str (e->cmd));
				break;
		}

		at_fifo_queue_rem (pvt);
	}
	else if (e)
	{
		ast_log (LOG_ERROR, "[%s] Received 'OK' when expecting '%s', ignoring\n", pvt->id, at_res2str (e->res));
	}
	else
	{
		ast_log (LOG_ERROR, "[%s] Received unexpected 'OK'\n", pvt->id);
	}

	return 0;

e_return:
	at_fifo_queue_rem (pvt);

	return -1;
}
Esempio n. 5
0
static char *timing_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
	struct ast_timer *timer;
	int count = 0;
	struct timeval start, end;
	unsigned int test_rate = 50;

	switch (cmd) {
	case CLI_INIT:
		e->command = "timing test";
		e->usage = "Usage: timing test <rate>\n"
		           "   Test a timer with a specified rate, 50/sec by default.\n"
		           "";
		return NULL;
	case CLI_GENERATE:
		return NULL;
	}

	if (a->argc != 2 && a->argc != 3) {
		return CLI_SHOWUSAGE;
	}

	if (a->argc == 3) {
		unsigned int rate;
		if (sscanf(a->argv[2], "%30u", &rate) == 1) {
			test_rate = rate;
		} else {
			ast_cli(a->fd, "Invalid rate '%s', using default of %u\n", a->argv[2], test_rate);
		}
	}

	ast_cli(a->fd, "Attempting to test a timer with %u ticks per second.\n", test_rate);

	if (!(timer = ast_timer_open())) {
		ast_cli(a->fd, "Failed to open timing fd\n");
		return CLI_FAILURE;
	}

	ast_cli(a->fd, "Using the '%s' timing module for this test.\n", timer->holder->iface->name);

	start = ast_tvnow();

	ast_timer_set_rate(timer, test_rate);

	while (ast_tvdiff_ms((end = ast_tvnow()), start) < 1000) {
		int res;
		struct pollfd pfd = {
			.fd = ast_timer_fd(timer),
			.events = POLLIN | POLLPRI,
		};

		res = ast_poll(&pfd, 1, 100);

		if (res == 1) {
			count++;
			if (ast_timer_ack(timer, 1) < 0) {
				ast_cli(a->fd, "Timer failed to acknowledge.\n");
				ast_timer_close(timer);
				return CLI_FAILURE;
			}
		} else if (!res) {
			ast_cli(a->fd, "poll() timed out!  This is bad.\n");
		} else if (errno != EAGAIN && errno != EINTR) {
			ast_cli(a->fd, "poll() returned error: %s\n", strerror(errno));
		}
	}

	ast_timer_close(timer);
	timer = NULL;

	ast_cli(a->fd, "It has been %" PRIi64 " milliseconds, and we got %d timer ticks\n",
		ast_tvdiff_ms(end, start), count);

	return CLI_SUCCESS;
}

static struct ast_cli_entry cli_timing[] = {
	AST_CLI_DEFINE(timing_test, "Run a timing test"),
};

static void timing_shutdown(void)
{
	ast_cli_unregister_multiple(cli_timing, ARRAY_LEN(cli_timing));

	ast_heap_destroy(timing_interfaces);
	timing_interfaces = NULL;
}
Esempio n. 6
0
struct ast_channel *stasis_app_control_snoop(struct ast_channel *chan,
	enum stasis_app_snoop_direction spy, enum stasis_app_snoop_direction whisper,
	const char *app, const char *app_args, const char *snoop_id)
{
	RAII_VAR(struct stasis_app_snoop *, snoop, NULL, ao2_cleanup);
	struct ast_format_cap *caps;
	pthread_t thread;
	struct ast_assigned_ids assignedids = {
		.uniqueid = snoop_id,
	};

	if (spy == STASIS_SNOOP_DIRECTION_NONE &&
		whisper == STASIS_SNOOP_DIRECTION_NONE) {
		return NULL;
	}

	snoop = ao2_alloc_options(sizeof(*snoop), snoop_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
	if (!snoop) {
		return NULL;
	}

	/* Allocate a buffer to store the Stasis application and arguments in */
	snoop->app = ast_str_create(64);
	if (!snoop->app) {
		return NULL;
	}

	ast_str_set(&snoop->app, 0, "%s", app);
	if (!ast_strlen_zero(app_args)) {
		ast_str_append(&snoop->app, 0, ",%s", app_args);
	}

	/* Set up a timer for the Snoop channel so it wakes up at a specific interval */
	snoop->timer = ast_timer_open();
	if (!snoop->timer) {
		return NULL;
	}
	ast_timer_set_rate(snoop->timer, 1000 / SNOOP_INTERVAL);

	/* Determine which signed linear format should be used */
	snoop_determine_format(chan, snoop);

	/* Allocate a Snoop channel and set up various parameters */
	snoop->chan = ast_channel_alloc(1, AST_STATE_UP, "", "", "", "", "", &assignedids, NULL, 0, "Snoop/%s-%08x", ast_channel_uniqueid(chan),
		(unsigned)ast_atomic_fetchadd_int((int *)&chan_idx, +1));
	if (!snoop->chan) {
		return NULL;
	}

	ast_copy_string(snoop->uniqueid, ast_channel_uniqueid(chan), sizeof(snoop->uniqueid));

	/* To keep the channel valid on the Snoop structure until it is destroyed we bump the ref up here */
	ast_channel_ref(snoop->chan);

	ast_channel_tech_set(snoop->chan, &snoop_tech);
	ao2_ref(snoop, +1);
	ast_channel_tech_pvt_set(snoop->chan, snoop);
	ast_channel_set_fd(snoop->chan, 0, ast_timer_fd(snoop->timer));

	/* The format on the Snoop channel will be this signed linear format, and it will never change */
	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
	if (!caps) {
		ast_channel_unlock(snoop->chan);
		ast_hangup(snoop->chan);
		return NULL;
	}
	ast_format_cap_append(caps, snoop->spy_format, 0);
	ast_channel_nativeformats_set(snoop->chan, caps);
	ao2_ref(caps, -1);

	ast_channel_set_writeformat(snoop->chan, snoop->spy_format);
	ast_channel_set_rawwriteformat(snoop->chan, snoop->spy_format);
	ast_channel_set_readformat(snoop->chan, snoop->spy_format);
	ast_channel_set_rawreadformat(snoop->chan, snoop->spy_format);

	ast_channel_unlock(snoop->chan);

	if (spy != STASIS_SNOOP_DIRECTION_NONE) {
		if (snoop_setup_audiohook(chan, AST_AUDIOHOOK_TYPE_SPY, spy, &snoop->spy_direction, &snoop->spy)) {
			ast_hangup(snoop->chan);
			return NULL;
		}

		snoop->spy_samples = ast_format_get_sample_rate(snoop->spy_format) / (1000 / SNOOP_INTERVAL);
		snoop->spy_active = 1;
	}

	/* If whispering is enabled set up the audiohook */
	if (whisper != STASIS_SNOOP_DIRECTION_NONE) {
		if (snoop_setup_audiohook(chan, AST_AUDIOHOOK_TYPE_WHISPER, whisper, &snoop->whisper_direction, &snoop->whisper)) {
			ast_hangup(snoop->chan);
			return NULL;
		}

		snoop->whisper_active = 1;
	}

	/* Create the thread which services the Snoop channel */
	ao2_ref(snoop, +1);
	if (ast_pthread_create_detached_background(&thread, NULL, snoop_stasis_thread, snoop)) {
		ao2_cleanup(snoop);

		/* No other thread is servicing this channel so we can immediately hang it up */
		ast_hangup(snoop->chan);
		return NULL;
	}

	publish_chanspy_message(snoop, 1);

	/* The caller of this has a reference as well */
	return ast_channel_ref(snoop->chan);
}
Esempio n. 7
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;
}