Exemple #1
0
static struct ast_channel *rec_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
{
	struct ast_channel *chan;
	struct ast_format format;
	const char *conf_name = data;

	chan = ast_channel_alloc(1, AST_STATE_UP, NULL, NULL, NULL, NULL, NULL, NULL, 0,
		"CBRec/conf-%s-uid-%d",
		conf_name, (int) ast_random());
	if (!chan) {
		return NULL;
	}
	if (ast_channel_add_bridge_role(chan, "recorder")) {
		ast_channel_release(chan);
		return NULL;
	}
	ast_format_set(&format, AST_FORMAT_SLINEAR, 0);
	ast_channel_tech_set(chan, conf_record_get_tech());
	ast_format_cap_add_all(ast_channel_nativeformats(chan));
	ast_format_copy(ast_channel_writeformat(chan), &format);
	ast_format_copy(ast_channel_rawwriteformat(chan), &format);
	ast_format_copy(ast_channel_readformat(chan), &format);
	ast_format_copy(ast_channel_rawreadformat(chan), &format);
	return chan;
}
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_codec_interp_len(&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);
			ast_format_copy(&jb->last_format, &f->subclass.format);
			ast_frfree(f);
			break;
		case AST_JB_IMPL_INTERP:
			/* interpolate a frame */
			f = &finterp;
			ast_format_copy(&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);
	}
}
/*! \brief Prepend codec to list */
void ast_codec_pref_prepend(struct ast_codec_pref *pref, struct ast_format *format, int only_if_existing)
{
	int x, newindex = 0;
	size_t f_len = 0;
	const struct ast_format_list *f_list = ast_format_list_get(&f_len);

	/* First step is to get the codecs "index number" */
	for (x = 0; x < f_len; x++) {
		if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
			newindex = x + 1;
			break;
		}
	}
	/* Done if its unknown */
	if (!newindex) {
		ast_format_list_destroy(f_list);
		return;
	}

	/* Now find any existing occurrence, or the end */
	for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
		if (!pref->order[x] || pref->order[x] == newindex)
			break;
	}

	/* If we failed to find any occurrence, set to the end */
	if (x == AST_CODEC_PREF_SIZE) {
		--x;
	}

	if (only_if_existing && !pref->order[x]) {
		ast_format_list_destroy(f_list);
		return;
	}

	/* Move down to make space to insert - either all the way to the end,
	   or as far as the existing location (which will be overwritten) */
	for (; x > 0; x--) {
		pref->order[x] = pref->order[x - 1];
		pref->framing[x] = pref->framing[x - 1];
		ast_format_copy(&pref->formats[x], &pref->formats[x - 1]);
	}

	/* And insert the new entry */
	pref->order[0] = newindex;
	pref->framing[0] = 0; /* ? */
	ast_format_copy(&pref->formats[0], format);
	ast_format_list_destroy(f_list);
}
Exemple #4
0
/*! \brief Append all codecs to a preference list, without distrubing existing order */
void ast_codec_pref_append_all(struct ast_codec_pref *pref)
{
	int x, y, found;
	size_t f_len = 0;
	const struct ast_format_list *f_list = ast_format_list_get(&f_len);

	/* leave any existing entries, and don't create duplicates (e.g. allow=ulaw,all) */
	for (x = 0; x < f_len; x++) {
		/* x = codec to add */
		found = 0;
		for (y = 0; y < f_len; y++) {
			/* y = scan of existing preferences */
			if (!pref->order[y]) {
				break;
			}
			if (x + 1 == pref->order[y]) {
				found = 1;
				break;
			}
		}
		if (found) {
			continue;
		}
		for (; y < f_len; y++) {
			/* add x to the end of y */
			if (!pref->order[y])
			{
				pref->order[y] = x + 1;
				ast_format_copy(&pref->formats[y], &f_list[x].format);
				break;
			}
		}
	}
}
Exemple #5
0
static void *playtones_alloc(struct ast_channel *chan, void *params)
{
	struct playtones_def *pd = params;
	struct playtones_state *ps = NULL;

	if (!(ps = ast_calloc(1, sizeof(*ps)))) {
		return NULL;
	}

	ast_format_copy(&ps->origwfmt, ast_channel_writeformat(chan));

	if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR)) {
		ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", ast_channel_name(chan));
		playtones_release(NULL, ps);
		ps = NULL;
	} else {
		ps->vol = pd->vol;
		ps->reppos = pd->reppos;
		ps->nitems = pd->nitems;
		ps->items = pd->items;
		ps->oldnpos = -1;
	}

	/* Let interrupts interrupt :) */
	if (pd->interruptible) {
		ast_set_flag(ast_channel_flags(chan), AST_FLAG_WRITE_INT);
	} else {
		ast_clear_flag(ast_channel_flags(chan), AST_FLAG_WRITE_INT);
	}

	return ps;
}
Exemple #6
0
void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right)
{
	size_t f_len;
	const const struct ast_format_list *f_list = ast_format_list_get(&f_len);
	int x, differential = (int) 'A', mem;
	char *from, *to;

	/* TODO re-evaluate this function.  It is using the order of the formats specified
	 * in the global format list in a way that may not be safe. */
	if (right) {
		from = pref->order;
		to = buf;
		mem = size;
	} else {
		to = pref->order;
		from = buf;
		mem = AST_CODEC_PREF_SIZE;
	}

	memset(to, 0, mem);
	for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
		if (!from[x]) {
			break;
		}
		to[x] = right ? (from[x] + differential) : (from[x] - differential);
		if (!right && to[x] && (to[x] < f_len)) {
			ast_format_copy(&pref->formats[x], &f_list[to[x]-1].format);
		}
	}
	ast_format_list_destroy(f_list);
}
Exemple #7
0
/*! \brief Remove codec from pref list */
void ast_codec_pref_remove(struct ast_codec_pref *pref, struct ast_format *format)
{
	struct ast_codec_pref oldorder;
	int x, y = 0;
	size_t f_len = 0;
	const const struct ast_format_list *f_list;

	if (!pref->order[0]) {
		return;
	}

	f_list = ast_format_list_get(&f_len);
	memcpy(&oldorder, pref, sizeof(oldorder));
	memset(pref, 0, sizeof(*pref));

	for (x = 0; x < f_len; x++) {
		if (!oldorder.order[x]) {
			break;
		}
		if (ast_format_cmp(&f_list[oldorder.order[x]-1].format, format) == AST_FORMAT_CMP_NOT_EQUAL) {
			pref->order[y] = oldorder.order[x];
			ast_format_copy(&pref->formats[y], &oldorder.formats[x]);
			pref->framing[y++] = oldorder.framing[x];
		}
	}
	ast_format_list_destroy(f_list);
}
Exemple #8
0
/*! \brief Append codec to list */
int ast_codec_pref_append(struct ast_codec_pref *pref, struct ast_format *format)
{
	int x, newindex = 0;
	size_t f_len = 0;
	const struct ast_format_list *f_list = ast_format_list_get(&f_len);

	ast_codec_pref_remove(pref, format);

	for (x = 0; x < f_len; x++) {
		if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
			newindex = x + 1;
			break;
		}
	}

	if (newindex) {
		for (x = 0; x < f_len; x++) {
			if (!pref->order[x]) {
				pref->order[x] = newindex;
				ast_format_copy(&pref->formats[x], format);
				break;
			}
		}
	}

	ast_format_list_destroy(f_list);
	return x;
}
Exemple #9
0
static int measurenoise(struct ast_channel *chan, int ms, char *who)
{
    int res=0;
    int mssofar;
    int noise=0;
    int samples=0;
    int x;
    short *foo;
    struct timeval start;
    struct ast_frame *f;
    struct ast_format rformat;

    ast_format_copy(&rformat, ast_channel_readformat(chan));
    if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR)) {
        ast_log(LOG_NOTICE, "Unable to set to linear mode!\n");
        return -1;
    }
    start = ast_tvnow();
    for(;;) {
        mssofar = ast_tvdiff_ms(ast_tvnow(), start);
        if (mssofar > ms)
            break;
        res = ast_waitfor(chan, ms - mssofar);
        if (res < 1)
            break;
        f = ast_read(chan);
        if (!f) {
            res = -1;
            break;
        }
        if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.format.id == AST_FORMAT_SLINEAR)) {
            foo = (short *)f->data.ptr;
            for (x=0; x<f->samples; x++) {
                noise += abs(foo[x]);
                samples++;
            }
        }
        ast_frfree(f);
    }

    if (rformat.id) {
        if (ast_set_read_format(chan, &rformat)) {
            ast_log(LOG_NOTICE, "Unable to restore original format!\n");
            return -1;
        }
    }
    if (res < 0)
        return res;
    if (!samples) {
        ast_log(LOG_NOTICE, "No samples were received from the other side!\n");
        return -1;
    }
    ast_debug(1, "%s: Noise: %d, samples: %d, avg: %d\n", who, noise, samples, noise / samples);
    return (noise / samples);
}
Exemple #10
0
struct ast_format *ast_codec_pref_index(struct ast_codec_pref *pref, int idx, struct ast_format *result)
{
	if ((idx >= 0) && (idx < sizeof(pref->order)) && pref->formats[idx].id) {
		ast_format_copy(result, &pref->formats[idx]);
	} else {
		ast_format_clear(result);
		return NULL;
	}

	return result;
}
Exemple #11
0
static int find_best_byid_cb(void *obj, void *arg, int flag)
{
	struct ast_format *format = obj;
	struct byid_data *data = arg;

	if (data->id != format->id) {
		return 0;
	}
	if (!data->result->id || (ast_format_rate(data->result) < ast_format_rate(format))) {
		ast_format_copy(data->result, format);
	}
	return 0;
}
Exemple #12
0
int ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const struct ast_format *format, struct ast_format *result)
{
	struct ast_format *f;
	struct ast_format_cap *tmp_cap = (struct ast_format_cap *) cap;
	f = ao2_find(tmp_cap->formats, (struct ast_format *) format, OBJ_POINTER | tmp_cap->nolock);

	if (f) {
		ast_format_copy(result, f);
		ao2_ref(f, -1);
		return 1;
	}
	ast_format_clear(result);
	return 0;
}
Exemple #13
0
/*! \brief Called when we want to place a call somewhere, but not actually call it... yet */
static struct ast_channel *bridge_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, void *data, int *cause)
{
	struct bridge_pvt *p = NULL;
	struct ast_format slin;

	/* Try to allocate memory for our very minimal pvt structure */
	if (!(p = ao2_alloc(sizeof(*p), NULL))) {
		return NULL;
	}

	/* Try to grab two Asterisk channels to use as input and output channels */
	if (!(p->input = ast_channel_alloc(1, AST_STATE_UP, 0, 0, "", "", "", requestor ? requestor->linkedid : NULL, 0, "Bridge/%p-input", p))) {
		ao2_ref(p, -1);
		return NULL;
	}
	if (!(p->output = ast_channel_alloc(1, AST_STATE_UP, 0, 0, "", "", "", requestor ? requestor->linkedid : NULL, 0, "Bridge/%p-output", p))) {
		p->input = ast_channel_release(p->input);
		ao2_ref(p, -1);
		return NULL;
	}

	/* Setup parameters on both new channels */
	p->input->tech = p->output->tech = &bridge_tech;

	ao2_ref(p, 2);
	p->input->tech_pvt = p->output->tech_pvt = p;

	ast_format_set(&slin, AST_FORMAT_SLINEAR, 0);

	ast_format_cap_add(p->input->nativeformats, &slin);
	ast_format_cap_add(p->output->nativeformats, &slin);
	ast_format_copy(&p->input->readformat, &slin);
	ast_format_copy(&p->output->readformat, &slin);
	ast_format_copy(&p->input->rawreadformat, &slin);
	ast_format_copy(&p->output->rawreadformat, &slin);
	ast_format_copy(&p->input->writeformat, &slin);
	ast_format_copy(&p->output->writeformat, &slin);
	ast_format_copy(&p->input->rawwriteformat, &slin);
	ast_format_copy(&p->output->rawwriteformat, &slin);

	ast_answer(p->output);
	ast_answer(p->input);

	/* remove the reference from the alloc. The channels now own the pvt. */
	ao2_ref(p, -1);
	return p->input;
}
Exemple #14
0
static int dahdiscan_exec(struct ast_channel *chan, const char *data)
{
	const char *spec = "DAHDI";
	struct ast_flags flags;
	struct spy_dtmf_options user_options = {
		.cycle = '#',
		.volume = '\0',
		.exit = '*',
	};
	struct ast_format oldwf;
	int res;
	char *mygroup = NULL;

	/* Coverity - This uninit_use should be ignored since this macro initializes the flags */
	ast_clear_flag(&flags, AST_FLAGS_ALL);
	ast_format_clear(&oldwf);
	if (!ast_strlen_zero(data)) {
		mygroup = ast_strdupa(data);
	}
	ast_set_flag(&flags, OPTION_DTMF_EXIT);
	ast_set_flag(&flags, OPTION_DTMF_CYCLE);
	ast_set_flag(&flags, OPTION_DAHDI_SCAN);

	ast_format_copy(&oldwf, ast_channel_writeformat(chan));
	if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
		ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
		return -1;
	}

	res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL);

	if (oldwf.id && ast_set_write_format(chan, &oldwf) < 0)
		ast_log(LOG_ERROR, "Could Not Set Write Format.\n");

	return res;
}

static int unload_module(void)
{
	int res = 0;

	res |= ast_unregister_application(app_chan);
	res |= ast_unregister_application(app_ext);
	res |= ast_unregister_application(app_dahdiscan);

	return res;
}
Exemple #15
0
void ast_format_cap_add(struct ast_format_cap *cap, const struct ast_format *format)
{
	struct ast_format *fnew;

	if (!format || !format->id) {
		return;
	}
	if (!(fnew = ao2_alloc(sizeof(struct ast_format), NULL))) {
		return;
	}
	ast_format_copy(fnew, format);
	if (cap->nolock) {
		ao2_link_nolock(cap->formats, fnew);
	} else {
		ao2_link(cap->formats, fnew);
	}
	ao2_ref(fnew, -1);
}
Exemple #16
0
struct ast_format *ast_getformatbyname(const char *name, struct ast_format *result)
{
	int x;
	size_t f_len;
	const struct ast_format_list *f_list = ast_format_list_get(&f_len);

	for (x = 0; x < f_len; x++) {
		if (!strcasecmp(f_list[x].name, name) ||
			 !strcasecmp(f_list[x].name, ast_expand_codec_alias(name))) {

			ast_format_copy(result, &f_list[x].format);
			f_list = ast_format_list_destroy(f_list);
			return result;
		}
	}
	f_list = ast_format_list_destroy(f_list);

	return NULL;
}
static struct ast_frame *pcm_read(struct ast_filestream *s, int *whennext)
{
	int res;
	
	/* Send a frame from the file to the appropriate channel */

	s->fr.frametype = AST_FRAME_VOICE;
	ast_format_copy(&s->fr.subclass.format, &s->fmt->format);
	s->fr.mallocd = 0;
	AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
	if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) < 1) {
		if (res)
			ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
		return NULL;
	}
	s->fr.datalen = res;
	if (s->fmt->format.id == AST_FORMAT_G722)
		*whennext = s->fr.samples = res * 2;
	else
		*whennext = s->fr.samples = res;
	return &s->fr;
}
Exemple #18
0
static int transmit_audio(fax_session *s)
{
	int res = -1;
	struct ast_format original_read_fmt;
	struct ast_format original_write_fmt;
	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,
*/
	};

	ast_format_clear(&original_read_fmt);
	ast_format_clear(&original_write_fmt);

	/* 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

	ast_format_copy(&original_read_fmt, ast_channel_readformat(s->chan));
	if (original_read_fmt.id != AST_FORMAT_SLINEAR) {
		res = ast_set_read_format_by_id(s->chan, AST_FORMAT_SLINEAR);
		if (res < 0) {
			ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
			goto done;
		}
	}

	ast_format_copy(&original_write_fmt, ast_channel_writeformat(s->chan));
	if (original_write_fmt.id != AST_FORMAT_SLINEAR) {
		res = ast_set_write_format_by_id(s->chan, AST_FORMAT_SLINEAR);
		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/%u, len=%d\n", inf->frametype, (unsigned int) inf->subclass.format.id, 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 && inf->subclass.format.id == AST_FORMAT_SLINEAR) {
			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.id != AST_FORMAT_SLINEAR) {
		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));
	}

	if (original_read_fmt.id != AST_FORMAT_SLINEAR) {
		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));
	}

	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;
}
Exemple #19
0
int AST_OPTIONAL_API_NAME(ast_adsi_transmit_message_full)(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype, int dowait)
{
	unsigned char *msgs[5] = { NULL, NULL, NULL, NULL, NULL };
	int msglens[5], msgtypes[5], newdatamode = (ast_channel_adsicpe(chan) & ADSI_FLAG_DATAMODE), res, x, waitforswitch = 0;
	struct ast_format writeformat;
	struct ast_format readformat;

	ast_format_copy(&writeformat, ast_channel_writeformat(chan));
	ast_format_copy(&readformat, ast_channel_readformat(chan));

	for (x = 0; x < msglen; x += (msg[x+1]+2)) {
		if (msg[x] == ADSI_SWITCH_TO_DATA) {
			ast_debug(1, "Switch to data is sent!\n");
			waitforswitch++;
			newdatamode = ADSI_FLAG_DATAMODE;
		}

		if (msg[x] == ADSI_SWITCH_TO_VOICE) {
			ast_debug(1, "Switch to voice is sent!\n");
			waitforswitch++;
			newdatamode = 0;
		}
	}
	msgs[0] = msg;

	msglens[0] = msglen;
	msgtypes[0] = msgtype;

	if (msglen > 253) {
		ast_log(LOG_WARNING, "Can't send ADSI message of %d bytes, too large\n", msglen);
		return -1;
	}

	ast_stopstream(chan);

	if (ast_set_write_format_by_id(chan, AST_FORMAT_ULAW)) {
		ast_log(LOG_WARNING, "Unable to set write format to ULAW\n");
		return -1;
	}

	if (ast_set_read_format_by_id(chan, AST_FORMAT_ULAW)) {
		ast_log(LOG_WARNING, "Unable to set read format to ULAW\n");
		if (writeformat.id) {
			if (ast_set_write_format(chan, &writeformat)) {
				ast_log(LOG_WARNING, "Unable to restore write format to %s\n", ast_getformatname(&writeformat));
			}
		}
		return -1;
	}
	res = __adsi_transmit_messages(chan, msgs, msglens, msgtypes);

	if (dowait) {
		ast_debug(1, "Wait for switch is '%d'\n", waitforswitch);
		while (waitforswitch-- && ((res = ast_waitfordigit(chan, 1000)) > 0)) {
			res = 0;
			ast_debug(1, "Waiting for 'B'...\n");
		}
	}

	if (!res) {
		ast_channel_adsicpe_set(chan, (ast_channel_adsicpe(chan) & ~ADSI_FLAG_DATAMODE) | newdatamode);
	}

	if (writeformat.id) {
		ast_set_write_format(chan, &writeformat);
	}
	if (readformat.id) {
		ast_set_read_format(chan, &readformat);
	}

	if (!res) {
		res = ast_safe_sleep(chan, 100 );
	}
	return res;
}
Exemple #20
0
static int NBScat_exec(struct ast_channel *chan, const char *data)
{
	int res=0;
	int fds[2];
	int ms = -1;
	int pid = -1;
	struct ast_format owriteformat;
	struct timeval next;
	struct ast_frame *f;
	struct myframe {
		struct ast_frame f;
		char offset[AST_FRIENDLY_OFFSET];
		short frdata[160];
	} myf;

	ast_format_clear(&owriteformat);
	if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds)) {
		ast_log(LOG_WARNING, "Unable to create socketpair\n");
		return -1;
	}
	
	ast_stopstream(chan);

	ast_format_copy(&owriteformat, &chan->writeformat);
	res = ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR);
	if (res < 0) {
		ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
		return -1;
	}
	
	res = NBScatplay(fds[1]);
	/* 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));
				if (res > 0) {
					myf.f.frametype = AST_FRAME_VOICE;
					ast_format_set(&myf.f.subclass.format, AST_FORMAT_SLINEAR, 0);
					myf.f.datalen = res;
					myf.f.samples = res / 2;
					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;
					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, 8000));
			} 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.id)
		ast_set_write_format(chan, &owriteformat);

	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, },
	};

	ast_format_clear(&owriteformat);
	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);
	
	ast_format_copy(&owriteformat, ast_channel_writeformat(chan));
	res = ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR);
	if (res < 0) {
		ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
		return -1;
	}
	
	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.frametype = AST_FRAME_VOICE;
					ast_format_set(&myf.f.subclass.format, AST_FORMAT_SLINEAR, 0);
					myf.f.datalen = res;
					myf.f.samples = res / 2;
					myf.f.offset = AST_FRIENDLY_OFFSET;
					myf.f.src = __PRETTY_FUNCTION__;
					myf.f.data.ptr = myf.frdata;
					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.id)
		ast_set_write_format(chan, &owriteformat);
	return res;
}
Exemple #22
0
int ast_format_cap_has_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
{
	struct ao2_iterator it;
	struct ast_format *tmp;
	struct find_joint_data data = {
		.joint_found = 0,
		.joint_cap = NULL,
	};

	it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0);
	while ((tmp = ao2_iterator_next(&it))) {
		data.format = tmp;
		ao2_callback(cap2->formats,
			OBJ_MULTIPLE | OBJ_NODATA | cap2->nolock,
			find_joint_cb,
			&data);
		ao2_ref(tmp, -1);
	}
	ao2_iterator_destroy(&it);

	return data.joint_found ? 1 : 0;
}

int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
{
	struct ao2_iterator it;
	struct ast_format *tmp;

	if (ao2_container_count(cap1->formats) != ao2_container_count(cap2->formats)) {
		return 0; /* if they are not the same size, they are not identical */
	}

	it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0);
	while ((tmp = ao2_iterator_next(&it))) {
		if (!ast_format_cap_iscompatible(cap2, tmp)) {
			ao2_ref(tmp, -1);
			ao2_iterator_destroy(&it);
			return 0;
		}
		ao2_ref(tmp, -1);
	}
	ao2_iterator_destroy(&it);

	return 1;
}

struct ast_format_cap *ast_format_cap_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
{
	struct ao2_iterator it;
	struct ast_format_cap *result = ast_format_cap_alloc_nolock();
	struct ast_format *tmp;
	struct find_joint_data data = {
		.joint_found = 0,
		.joint_cap = result,
	};
	if (!result) {
		return NULL;
	}

	it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0);
	while ((tmp = ao2_iterator_next(&it))) {
		data.format = tmp;
		ao2_callback(cap2->formats,
			OBJ_MULTIPLE | OBJ_NODATA | cap2->nolock,
			find_joint_cb,
			&data);
		ao2_ref(tmp, -1);
	}
	ao2_iterator_destroy(&it);

	if (ao2_container_count(result->formats)) {
		return result;
	}

	result = ast_format_cap_destroy(result);
	return NULL;
}

static int joint_copy_helper(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result, int append)
{
	struct ao2_iterator it;
	struct ast_format *tmp;
	struct find_joint_data data = {
		.joint_cap = result,
		.joint_found = 0,
	};
	if (!append) {
		ast_format_cap_remove_all(result);
	}
	it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0);
	while ((tmp = ao2_iterator_next(&it))) {
		data.format = tmp;
		ao2_callback(cap2->formats,
			OBJ_MULTIPLE | OBJ_NODATA | cap2->nolock,
			find_joint_cb,
			&data);
		ao2_ref(tmp, -1);
	}
	ao2_iterator_destroy(&it);

	return ao2_container_count(result->formats) ? 1 : 0;
}

int ast_format_cap_joint_append(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
{
	return joint_copy_helper(cap1, cap2, result, 1);
}

int ast_format_cap_joint_copy(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
{
	return joint_copy_helper(cap1, cap2, result, 0);
}

struct ast_format_cap *ast_format_cap_get_type(const struct ast_format_cap *cap, enum ast_format_type ftype)
{
	struct ao2_iterator it;
	struct ast_format_cap *result = ast_format_cap_alloc_nolock();
	struct ast_format *tmp;

	if (!result) {
		return NULL;
	}

	/* for each format in cap1, see if that format is
	 * compatible with cap2. If so copy it to the result */
	it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
	while ((tmp = ao2_iterator_next(&it))) {
		if (AST_FORMAT_GET_TYPE(tmp->id) == ftype) {
			/* copy format */
			ast_format_cap_add(result, tmp);
		}
		ao2_ref(tmp, -1);
	}
	ao2_iterator_destroy(&it);

	if (ao2_container_count(result->formats)) {
		return result;
	}
	result = ast_format_cap_destroy(result);

	return NULL;
}


int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_format_type type)
{
	struct ao2_iterator it;
	struct ast_format *tmp;

	it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
	while ((tmp = ao2_iterator_next(&it))) {
		if (AST_FORMAT_GET_TYPE(tmp->id) == type) {
			ao2_ref(tmp, -1);
			ao2_iterator_destroy(&it);
			return 1;
		}
		ao2_ref(tmp, -1);
	}
	ao2_iterator_destroy(&it);

	return 0;
}

void ast_format_cap_iter_start(struct ast_format_cap *cap)
{
	if (!cap->nolock) {
		ao2_lock(cap->formats);
	}
	cap->it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
}

void ast_format_cap_iter_end(struct ast_format_cap *cap)
{
	ao2_iterator_destroy(&cap->it);
	if (!cap->nolock) {
		ao2_unlock(cap->formats);
	}
}

int ast_format_cap_iter_next(struct ast_format_cap *cap, struct ast_format *format)
{
	struct ast_format *tmp = ao2_iterator_next(&cap->it);

	if (!tmp) {
		return -1;
	}
	ast_format_copy(format, tmp);
	ao2_ref(tmp, -1);

	return 0;
}

char *ast_getformatname_multiple(char *buf, size_t size, struct ast_format_cap *cap)
{
	int x;
	unsigned len;
	char *start, *end = buf;
	struct ast_format tmp_fmt;
	size_t f_len;
	const struct ast_format_list *f_list = ast_format_list_get(&f_len);

	if (!size) {
		f_list = ast_format_list_destroy(f_list);
		return buf;
	}
	snprintf(end, size, "(");
	len = strlen(end);
	end += len;
	size -= len;
	start = end;
	for (x = 0; x < f_len; x++) {
		ast_format_copy(&tmp_fmt, &f_list[x].format);
		if (ast_format_cap_iscompatible(cap, &tmp_fmt)) {
			snprintf(end, size, "%s|", f_list[x].name);
			len = strlen(end);
			end += len;
			size -= len;
		}
	}
	if (start == end) {
		ast_copy_string(start, "nothing)", size);
	} else if (size > 1) {
		*(end - 1) = ')';
	}
	f_list = ast_format_list_destroy(f_list);
	return buf;
}

uint64_t ast_format_cap_to_old_bitfield(const struct ast_format_cap *cap)
{
	uint64_t res = 0;
	struct ao2_iterator it;
	struct ast_format *tmp;

	it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
	while ((tmp = ao2_iterator_next(&it))) {
		res |= ast_format_to_old_bitfield(tmp);
		ao2_ref(tmp, -1);
	}
	ao2_iterator_destroy(&it);
	return res;
}
Exemple #23
0
static int app_exec(struct ast_channel *chan, const char *data)
{
	int res = 0, argc = 0, max_digits = 0, timeout = 0, alreadyran = 0;
	int ms, len, availatend;
	char *argv[3], *parse = NULL, *text = NULL, *rc = NULL;
	char tmp_exten[2], results[20];
	struct ast_module_user *u;
	struct ast_frame *f;
	struct timeval next;
	struct stuff *ps;
	struct ast_format oldwf;

	struct myframe {
		struct ast_frame f;
		char offset[AST_FRIENDLY_OFFSET];
		char frdata[framesize];
	} myf;

	ast_format_clear(&oldwf);

	swift_engine *engine;
	swift_port *port = NULL;
	swift_voice *voice;
	swift_params *params;
	swift_result_t sresult;
	swift_background_t tts_stream;
	unsigned int event_mask;

	memset(results, 0 ,20);
	memset(tmp_exten, 0, 2);
	memset(argv, 0, 3);

	parse = ast_strdupa(data);
	u = ast_module_user_add(chan);
	argc = ast_app_separate_args(parse, '|', argv, 3);
	text = argv[0];

	if (!ast_strlen_zero(argv[1])) {
		timeout = strtol(argv[1], NULL, 0);
	}
	if (!ast_strlen_zero(argv[2])) {
		max_digits = strtol(argv[2], NULL, 0);
	}
	if (ast_strlen_zero(text)) {
		ast_log(LOG_WARNING, "%s requires text to speak!\n", app);
		return -1;
	}
	if (!ast_strlen_zero(text)) {
		ast_log(LOG_DEBUG, "Text to Speak : %s\n", text);
	}
	if (timeout > 0) {
		ast_log(LOG_DEBUG, "Timeout : %d\n", timeout);
	}
	if (max_digits > 0) {
		ast_log(LOG_DEBUG, "Max Digits : %d\n", max_digits);
	}

	ps = malloc(sizeof(struct stuff));
	swift_init_stuff(ps);

	/* Setup synthesis */

	if ((engine = swift_engine_open(NULL)) == NULL) {
		ast_log(LOG_ERROR, "Failed to open Swift Engine.\n");
		goto exception;
	}

	params = swift_params_new(NULL);
	swift_params_set_string(params, "audio/encoding", "ulaw");
	swift_params_set_string(params, "audio/sampling-rate", "8000");
	swift_params_set_string(params, "audio/output-format", "raw");
	swift_params_set_string(params, "tts/text-encoding", "utf-8");

	/* Additional swift parameters
	 *
	 * swift_params_set_float(params, "speech/pitch/shift", 1.0);
	 * swift_params_set_int(params, "speech/rate", 150);
	 * swift_params_set_int(params, "audio/volume", 110);
	 * swift_params_set_int(params, "audio/deadair", 0);
	 */

	if ((port = swift_port_open(engine, params)) == NULL) {
		ast_log(LOG_ERROR, "Failed to open Swift Port.\n");
		goto exception;
	}
	if ((voice = swift_port_set_voice_by_name(port, cfg_voice)) == NULL) {
		ast_log(LOG_ERROR, "Failed to set voice.\n");
		goto exception;
	}

	event_mask = SWIFT_EVENT_AUDIO | SWIFT_EVENT_END;
	swift_port_set_callback(port, &swift_cb, event_mask, ps);

	if (SWIFT_FAILED(swift_port_speak_text(port, text, 0, NULL, &tts_stream, NULL))) {
		ast_log(LOG_ERROR, "Failed to speak.\n");
		goto exception;
	}
	if (chan->_state != AST_STATE_UP) {
		ast_answer(chan);
	}

	ast_stopstream(chan);

	ast_format_copy(&oldwf, &chan->writeformat);

	if (ast_set_write_format_by_id(chan, AST_FORMAT_ULAW) < 0) {
		ast_log(LOG_WARNING, "Unable to set write format.\n");
		goto exception;
	}

	res = 0;

	/* Wait 100ms first for synthesis to start crankin'; if that's not
	 * enough the
	 */

	next = ast_tvadd(ast_tvnow(), ast_tv(0, 100000));

	while (swift_generator_running(ps)) {
		ms = ast_tvdiff_ms(next, ast_tvnow());

		if (ms <= 0) {
			if (swift_bytes_available(ps) > 0) {
				ASTOBJ_WRLOCK(ps);
				len = fmin(framesize, ps->qc);
				availatend = cfg_buffer_size - (ps->pq_r - ps->q);

				if (len > availatend) {
					/* read #1: to end of q buf */
					memcpy(myf.frdata, ps->pq_r, availatend);
					ps->qc -= availatend;

					/* read #2: reset to start of q buf and get rest */
					ps->pq_r = ps->q;
					memcpy(myf.frdata + availatend, ps->pq_r, len - availatend);
					ps->qc -= len - availatend;
					ps->pq_r += len - availatend;
				} else {
					ast_log(LOG_DEBUG, "Easy read; %d bytes and %d at end, %d free\n", len, availatend, cfg_buffer_size - ps->qc);
					memcpy(myf.frdata, ps->pq_r, len);
					ps->qc -= len;
					ps->pq_r += len;
				}

				myf.f.frametype = AST_FRAME_VOICE;
				ast_format_set(&myf.f.subclass.format, AST_FORMAT_ULAW, 0);
				myf.f.datalen = len;
				myf.f.samples = len;
				myf.f.data.ptr = myf.frdata;
				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;

				if (ast_write(chan, &myf.f) < 0) {
					ast_log(LOG_DEBUG, "ast_write failed\n");
				}

				ast_log(LOG_DEBUG, "wrote a frame of %d\n", len);

				if (ps->qc < 0) {
					ast_log(LOG_DEBUG, "queue claims to contain negative bytes. Huh? qc < 0\n");
				}

				ASTOBJ_UNLOCK(ps);
				next = ast_tvadd(next, ast_samp2tv(myf.f.samples, samplerate));
			} else {
				next = ast_tvadd(next, ast_samp2tv(framesize / 2, samplerate));
				ast_log(LOG_DEBUG, "Whoops, writer starved for audio\n");
			}
		} else {
			ms = ast_waitfor(chan, ms);

			if (ms < 0) {
				ast_log(LOG_DEBUG, "Hangup detected\n");
				res = -1;
				ASTOBJ_WRLOCK(ps);
				ps->immediate_exit = 1;
				ASTOBJ_UNLOCK(ps);
			} else if (ms) {
				f = ast_read(chan);

				if (!f) {
					ast_log(LOG_DEBUG, "Null frame == hangup() detected\n");
					res = -1;
					ASTOBJ_WRLOCK(ps);
					ps->immediate_exit = 1;
					ASTOBJ_UNLOCK(ps);
				} else {
					if (f->frametype == AST_FRAME_DTMF && timeout > 0 && max_digits > 0) {
						char originalDTMF = f->subclass.integer;
						alreadyran = 1;
						res = 0;
						ASTOBJ_WRLOCK(ps);
						ps->immediate_exit = 1;
						ASTOBJ_UNLOCK(ps);

						if (max_digits > 1) {
							rc = listen_for_dtmf(chan, timeout, max_digits - 1);
						}
						if (rc) {
							sprintf(results, "%c%s", originalDTMF, rc);
						} else {
							sprintf(results, "%c", originalDTMF);
						}

						ast_log(LOG_NOTICE, "DTMF = %s\n", results);
						pbx_builtin_setvar_helper(chan, "SWIFT_DTMF", results);
					}
				}
				ast_frfree(f);
			}
		}

		ASTOBJ_RDLOCK(ps);

		if (ps->immediate_exit && !ps->generating_done) {
			if (SWIFT_FAILED(sresult = swift_port_stop(port, tts_stream, SWIFT_EVENT_NOW))) {
				ast_log(LOG_NOTICE, "Early top of swift port failed\n");
			}
		}

		ASTOBJ_UNLOCK(ps);
	}
	if (alreadyran == 0 && timeout > 0 && max_digits > 0) {
		rc = listen_for_dtmf(chan, timeout, max_digits);

		if (rc != NULL) {
			sprintf(results, "%s", rc);
			ast_log(LOG_NOTICE, "DTMF = %s\n", results);
			pbx_builtin_setvar_helper(chan, "SWIFT_DTMF", results);
		}
	}
	if (max_digits >= 1 && results != NULL) {
		if (cfg_goto_exten) {
			ast_log(LOG_NOTICE, "GoTo(%s|%s|%d) : ", chan->context, results, 1);

			if (ast_exists_extension (chan, chan->context, results, 1, chan->caller.id.number.str)) {
				ast_log(LOG_NOTICE, "OK\n");
				ast_copy_string(chan->exten, results, sizeof(chan->exten) - 1);
				chan->priority = 0;
			} else {
				ast_log(LOG_NOTICE, "FAILED\n");
			}
		}
	}

	exception:

	if (port != NULL) {
		swift_port_close(port);
	}
	if (engine != NULL) {
		swift_engine_close(engine);
	}
	if (ps && ps->q) {
		ast_free(ps->q);
		ps->q = NULL;
	}
	if (ps) {
		ast_free(ps);
		ps = NULL;
	}
	if (!res) {
		ast_set_write_format(chan, &oldwf);
	}

	ast_module_user_remove(u);
	return res;
}
Exemple #24
0
struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap)
{
	struct ast_unreal_pvt *unreal;

	static const struct ast_jb_conf jb_conf = {
		.flags = 0,
		.max_size = -1,
		.resync_threshold = -1,
		.impl = "",
		.target_extra = -1,
	};

	unreal = ao2_alloc(size, destructor);
	if (!unreal) {
		return NULL;
	}
	unreal->reqcap = ast_format_cap_dup(cap);
	if (!unreal->reqcap) {
		ao2_ref(unreal, -1);
		return NULL;
	}

	memcpy(&unreal->jb_conf, &jb_conf, sizeof(unreal->jb_conf));

	return unreal;
}

struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
	const struct ast_channel_tech *tech, int semi1_state, int semi2_state,
	const char *exten, const char *context, const struct ast_assigned_ids *assignedids,
	const struct ast_channel *requestor, struct ast_callid *callid)
{
	struct ast_channel *owner;
	struct ast_channel *chan;
	struct ast_format fmt;
	struct ast_assigned_ids id1 = {NULL, NULL};
	struct ast_assigned_ids id2 = {NULL, NULL};
	int generated_seqno = ast_atomic_fetchadd_int((int *) &name_sequence, +1);

	/* set unique ids for the two channels */
	if (assignedids && !ast_strlen_zero(assignedids->uniqueid)) {
		id1.uniqueid = assignedids->uniqueid;
		id2.uniqueid = assignedids->uniqueid2;
	}

	/* if id1 given but not id2, use default of id1;2 */
	if (id1.uniqueid && ast_strlen_zero(id2.uniqueid)) {
		char *uniqueid2;

		uniqueid2 = ast_alloca(strlen(id1.uniqueid) + 2);
		strcpy(uniqueid2, id1.uniqueid);/* Safe */
		strcat(uniqueid2, ";2");/* Safe */
		id2.uniqueid = uniqueid2;
	}

	/*
	 * Allocate two new Asterisk channels
	 *
	 * Make sure that the ;2 channel gets the same linkedid as ;1.
	 * You can't pass linkedid to both allocations since if linkedid
	 * isn't set, then each channel will generate its own linkedid.
	 */
	if (!(owner = ast_channel_alloc(1, semi1_state, NULL, NULL, NULL,
			exten, context, &id1, requestor, 0,
			"%s/%s-%08x;1", tech->type, p->name, generated_seqno))) {
		ast_log(LOG_WARNING, "Unable to allocate owner channel structure\n");
		return NULL;
	}

	if (callid) {
		ast_channel_callid_set(owner, callid);
	}

	ast_channel_tech_set(owner, tech);
	ao2_ref(p, +1);
	ast_channel_tech_pvt_set(owner, p);

	ast_format_cap_copy(ast_channel_nativeformats(owner), p->reqcap);

	/* Determine our read/write format and set it on each channel */
	ast_best_codec(p->reqcap, &fmt);
	ast_format_copy(ast_channel_writeformat(owner), &fmt);
	ast_format_copy(ast_channel_rawwriteformat(owner), &fmt);
	ast_format_copy(ast_channel_readformat(owner), &fmt);
	ast_format_copy(ast_channel_rawreadformat(owner), &fmt);

	ast_set_flag(ast_channel_flags(owner), AST_FLAG_DISABLE_DEVSTATE_CACHE);

	ast_jb_configure(owner, &p->jb_conf);

	if (ast_channel_cc_params_init(owner, requestor
		? ast_channel_get_cc_config_params((struct ast_channel *) requestor) : NULL)) {
		ao2_ref(p, -1);
		ast_channel_unlock(owner);
		ast_channel_release(owner);
		return NULL;
	}

	p->owner = owner;
	ast_channel_unlock(owner);

	if (!(chan = ast_channel_alloc(1, semi2_state, NULL, NULL, NULL,
			exten, context, &id2, owner, 0,
			"%s/%s-%08x;2", tech->type, p->name, generated_seqno))) {
		ast_log(LOG_WARNING, "Unable to allocate chan channel structure\n");
		ao2_ref(p, -1);
		ast_channel_release(owner);
		return NULL;
	}

	if (callid) {
		ast_channel_callid_set(chan, callid);
	}

	ast_channel_tech_set(chan, tech);
	ao2_ref(p, +1);
	ast_channel_tech_pvt_set(chan, p);

	ast_format_cap_copy(ast_channel_nativeformats(chan), p->reqcap);

	/* Format was already determined when setting up owner */
	ast_format_copy(ast_channel_writeformat(chan), &fmt);
	ast_format_copy(ast_channel_rawwriteformat(chan), &fmt);
	ast_format_copy(ast_channel_readformat(chan), &fmt);
	ast_format_copy(ast_channel_rawreadformat(chan), &fmt);

	ast_set_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE);

	p->chan = chan;
	ast_channel_unlock(chan);

	return owner;
}
Exemple #25
0
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;

	ast_format_clear(&oreadformat);
	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;
	}

	ast_format_copy(&oreadformat, ast_channel_readformat(chan));
	res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR);
	if (res < 0) {
		close(fds[0]);
		close(fds[1]);
		ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
		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.id)
		ast_set_read_format(chan, &oreadformat);

	return res;
}
Exemple #26
0
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',
	};
	struct ast_format oldwf;
	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);
	ast_format_clear(&oldwf);

	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);
	}

	ast_format_copy(&oldwf, ast_channel_writeformat(chan));
	if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 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.id && ast_set_write_format(chan, &oldwf) < 0)
		ast_log(LOG_ERROR, "Could Not Set Write Format.\n");

	return res;
}
Exemple #27
0
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;
	struct ast_channel *bridged;
	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, jbconf->resync_threshold);
	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. */
	ast_format_copy(&jb->last_format, &frr->subclass.format);

	/* Create a frame log file */
	if (ast_test_flag(jbconf, AST_JB_LOG)) {
		char safe_logfile[30] = "/tmp/logfile-XXXXXX";
		int safe_fd;
		snprintf(name2, sizeof(name2), "%s", ast_channel_name(chan));
		if ((tmp = strchr(name2, '/'))) {
			*tmp = '#';
		}

		bridged = ast_bridged_channel(chan);
		/* 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));
		if ((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;
}
Exemple #28
0
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;
	struct ast_format rfmt;
	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;

	ast_format_copy(&rfmt, &chan->readformat); /* Set to linear mode */
	if ((res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR)) < 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_verb(6, "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.id && ast_set_read_format(chan, &rfmt)) {
		ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(&rfmt), chan->name);
	}
	ast_dsp_free(sildet);
	return res;
}
Exemple #29
0
/*! \brief Function called when we should prepare to call the destination */
static struct ast_channel *multicast_rtp_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
{
	char *tmp = ast_strdupa(data), *multicast_type = tmp, *destination, *control;
	struct ast_rtp_instance *instance;
	struct ast_sockaddr control_address;
	struct ast_sockaddr destination_address;
	struct ast_channel *chan;
	struct ast_format fmt;
	ast_best_codec(cap, &fmt);

	ast_sockaddr_setnull(&control_address);

	/* If no type was given we can't do anything */
	if (ast_strlen_zero(multicast_type)) {
		goto failure;
	}

	if (!(destination = strchr(tmp, '/'))) {
		goto failure;
	}
	*destination++ = '\0';

	if ((control = strchr(destination, '/'))) {
		*control++ = '\0';
		if (!ast_sockaddr_parse(&control_address, control,
					PARSE_PORT_REQUIRE)) {
			goto failure;
		}
	}

	if (!ast_sockaddr_parse(&destination_address, destination,
				PARSE_PORT_REQUIRE)) {
		goto failure;
	}

	if (!(instance = ast_rtp_instance_new("multicast", NULL, &control_address, multicast_type))) {
		goto failure;
	}

	if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, "", "", "", "", "", requestor ? ast_channel_linkedid(requestor) : "", 0, "MulticastRTP/%p", instance))) {
		ast_rtp_instance_destroy(instance);
		goto failure;
	}
	ast_rtp_instance_set_channel_id(instance, ast_channel_uniqueid(chan));
	ast_rtp_instance_set_remote_address(instance, &destination_address);

	ast_channel_tech_set(chan, &multicast_rtp_tech);

	ast_format_cap_add(ast_channel_nativeformats(chan), &fmt);
	ast_format_copy(ast_channel_writeformat(chan), &fmt);
	ast_format_copy(ast_channel_rawwriteformat(chan), &fmt);
	ast_format_copy(ast_channel_readformat(chan), &fmt);
	ast_format_copy(ast_channel_rawreadformat(chan), &fmt);

	ast_channel_tech_pvt_set(chan, instance);

	return chan;

failure:
	*cause = AST_CAUSE_FAILURE;
	return NULL;
}
/* And decode everything we can in the buffer */
static struct ast_frame *lintosilk_frameout(struct ast_trans_pvt *pvt)
{

  struct silk_coder_pvt *coder = pvt->pvt;
  SKP_int ret = 0;
  SKP_int16 nBytesOut = 0;
  int datalen = 0;
  int samples = 0;
  int numPackets = 0;
  struct ast_frame *f;

  /* we can only work on multiples of a 10 ms sample
   * and no more than encControl->packetSize.
   * So we shove in packetSize samples repeatedly until
   * we are out */

  /* We only do stuff if we have more than packetSize */
  if (pvt->samples < coder->encControl.packetSize) {
    return NULL;
  }

  while (pvt->samples >= coder->encControl.packetSize) {

    nBytesOut = SILK_BUFFER_SIZE_BYTES - datalen;
    ret = SKP_Silk_SDK_Encode(coder->psEnc,
                              &coder->encControl,
                              (SKP_int16*)(coder->buf + samples),
                              coder->encControl.packetSize,
                              (SKP_uint8*)(pvt->outbuf.ui8 + datalen),
                              &nBytesOut);
    if (ret) {
      ast_log(LOG_WARNING, "Silk_Encode returned %d\n", ret);
    }

    /* nBytesOut now holds the number of bytes encoded */
    datalen += nBytesOut;
    samples += coder->encControl.packetSize;
    pvt->samples -= coder->encControl.packetSize;
    if(nBytesOut > 0){
      /* if stuff came out, we have encoded a packet */
      numPackets++;
    }
  }

  /* Move the remaining buffer stuff down */
  if (pvt->samples) {
    memmove(coder->buf, coder->buf + samples, pvt->samples *2);
  }

  if(datalen == 0){
    /* we shoved a bunch of samples in, but got no packets
     * out. We return NULL to the caller, like
     * if we could not encode anything */
    return NULL;
  }

  /* we build the frame ourselves because we have an explicit dest */
  f = &pvt->f;
  f->samples = coder->encControl.packetSize * numPackets;
  f->datalen = datalen;
  f->frametype = AST_FRAME_VOICE;
  ast_format_copy(&f->subclass.format, &pvt->explicit_dst);
  f->mallocd = 0;
  f->offset = AST_FRIENDLY_OFFSET;
  f->src = pvt->t->name;
  f->data.ptr = pvt->outbuf.c;
  return ast_frisolate(f);
}