Пример #1
0
static int append_cb(void *obj, void *arg, int flag)
{
	struct ast_format_cap *result = (struct ast_format_cap *) arg;
	struct ast_format *format = (struct ast_format *) obj;

	if (!ast_format_cap_iscompatible(result, format)) {
		ast_format_cap_add(result, format);
	}

	return 0;
}
Пример #2
0
static int nv_detectfax_exec(struct ast_channel *chan, const char *data)
{
	int res = 0;
	char tmp[256] = "\0";
	char *p = NULL;
	char *waitstr = NULL;
	char *options = NULL;
	char *silstr = NULL;
	char *minstr = NULL;
	char *maxstr = NULL;
	struct ast_frame *fr = NULL;
	struct ast_frame *fr2 = NULL;
	int notsilent = 0;
	struct timeval start = {0, 0}, end = {0, 0};
	int waitdur = 4;
	int sildur = 1000;
	int mindur = 100;
	int maxdur = -1;
	int skipanswer = 0;
	int noextneeded = 0;
	int ignoredtmf = 0;
	int ignorefax = 0;
	int ignoretalk = 0;
	int x = 0;
	struct ast_format* origrformat = NULL;
	int features = 0;
	time_t timeout = 0;
	struct ast_dsp *dsp = NULL;
	
	struct ast_format_cap *cap;
	struct ast_format linearFormat;
	
	/* linear format capabilities */
	ast_format_set(&linearFormat, AST_FORMAT_SLINEAR, 0);
	cap = ast_format_cap_alloc_nolock();
	ast_format_cap_add(cap, &linearFormat);
	/* done */
	
	pbx_builtin_setvar_helper(chan, "FAX_DETECTED", "");
	pbx_builtin_setvar_helper(chan, "FAXEXTEN", "");
	pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", "");
	pbx_builtin_setvar_helper(chan, "TALK_DETECTED", "");
	
	if (data || !ast_strlen_zero(data)) {
		strncpy(tmp, data, sizeof(tmp)-1);
	}	
	
	p = tmp;
	
	waitstr = strsep(&p, ",");
	options = strsep(&p, ",");
	silstr = strsep(&p, ",");
	minstr = strsep(&p, ",");	
	maxstr = strsep(&p, ",");	
	
	if (waitstr) {
		if ((sscanf(waitstr, "%d", &x) == 1) && (x > 0))
			waitdur = x;
	}
	
	if (options) {
		if (strchr(options, 'n'))
			skipanswer = 1;
		if (strchr(options, 'x'))
			noextneeded = 1;
		if (strchr(options, 'd'))
			ignoredtmf = 1;
		if (strchr(options, 'f'))
			ignorefax = 1;
		if (strchr(options, 't'))
			ignoretalk = 1;
	}
	
	if (silstr) {
		if ((sscanf(silstr, "%d", &x) == 1) && (x > 0))
			sildur = x;
	}
	
	if (minstr) {
		if ((sscanf(minstr, "%d", &x) == 1) && (x > 0))
			mindur = x;
	}
	
	if (maxstr) {
		if ((sscanf(maxstr, "%d", &x) == 1) && (x > 0))
			maxdur = x;
	}
	
	ast_log(LOG_DEBUG, "Preparing detect of fax (waitdur=%dms, sildur=%dms, mindur=%dms, maxdur=%dms)\n", 
						waitdur, sildur, mindur, maxdur);
						
	//	LOCAL_USER_ADD(u);
// 	if (chan->_state != AST_STATE_UP && !skipanswer) {
	if (ast_channel_state(chan) != AST_STATE_UP && !skipanswer) {
		/* Otherwise answer unless we're supposed to send this while on-hook */
		res = ast_answer(chan);
	}
	if (!res) {
// 		origrformat = chan->readformat;
		origrformat = ast_channel_readformat(chan);
		
// 		if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR))) 
		if ((res = ast_set_read_format_from_cap(chan, cap)) ){
			ast_log(LOG_WARNING, "Unable to set read format to linear!\n");
		}
	}
	if (!(dsp = ast_dsp_new())) {
		ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
		res = -1;
	}
	
	if (dsp) {	
		if (!ignoretalk)
			; /* features |= DSP_FEATURE_SILENCE_SUPPRESS; */
		if (!ignorefax)
			features |= DSP_FEATURE_FAX_DETECT;
		//if (!ignoredtmf)
			features |= DSP_FEATURE_DIGIT_DETECT;
			
		ast_dsp_set_threshold(dsp, 256); 
		ast_dsp_set_features(dsp, features | DSP_DIGITMODE_RELAXDTMF);
		ast_dsp_set_digitmode(dsp, DSP_DIGITMODE_DTMF);
	}

	if (!res) {
		if (waitdur > 0)
			timeout = time(NULL) + (time_t)waitdur;

		while(ast_waitfor(chan, -1) > -1) {
			if (waitdur > 0 && time(NULL) > timeout) {
				res = 0;
				break;
			}

			fr = ast_read(chan);
			if (!fr) {
				ast_log(LOG_DEBUG, "Got hangup\n");
				res = -1;
				break;
			}

			fr2 = ast_dsp_process(chan, dsp, fr);
			if (!fr2) {
				ast_log(LOG_WARNING, "Bad DSP received (what happened?)\n");
				fr2 = fr;
			} 

			if (fr2->frametype == AST_FRAME_DTMF) {
				if (fr2->subclass.integer == 'f' && !ignorefax) {
					/* Fax tone -- Handle and return NULL */
					ast_log(LOG_DEBUG, "Fax detected on %s\n", ast_channel_name(chan));
					ast_log(LOG_DEBUG, "Fax detected on %s\n", ast_channel_name(chan));
					if (strcmp(ast_channel_exten(chan), "fax")) {
						ast_log(LOG_NOTICE, "Redirecting %s to fax extension\n", ast_channel_name(chan));
						pbx_builtin_setvar_helper(chan, "FAX_DETECTED", "1");
						pbx_builtin_setvar_helper(chan,"FAXEXTEN",ast_channel_exten(chan));								
						if (ast_exists_extension(chan, ast_channel_context(chan), "fax", 1, ast_channel_caller(chan)->id.number.str)) {
							/* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
// 							strncpy(ast_channel_exten(chan), "fax", sizeof(ast_channel_exten(chan))-1);
// 							chan->priority = 0;
							ast_channel_exten_set(chan, "fax");
							ast_channel_priority_set(chan, 0);
						} else
							ast_log(LOG_WARNING, "Fax detected, but no fax extension\n");
					} else
						ast_log(LOG_WARNING, "Already in a fax extension, not redirecting\n");

					res = 0;
					ast_frfree(fr);
					break;
				} else if (!ignoredtmf) {
					ast_log(LOG_DEBUG, "DTMF detected on %s\n", ast_channel_name(chan));
					char t[2];
					t[0] = fr2->subclass.integer;
					t[1] = '\0';
					if (noextneeded || ast_canmatch_extension(chan, ast_channel_context(chan), t, 1, ast_channel_caller(chan)->id.number.str)) {
						pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", "1");
						/* They entered a valid extension, or might be anyhow */
						if (noextneeded) {
							ast_log(LOG_NOTICE, "DTMF received (not matching to exten)\n");
							res = 0;
						} else {
							ast_log(LOG_NOTICE, "DTMF received (matching to exten)\n");
							res = fr2->subclass.integer;
						}
						ast_frfree(fr);
						break;
					} else
						ast_log(LOG_DEBUG, "Valid extension requested and DTMF did not match\n");
				}
// 			} else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass == AST_FORMAT_SLINEAR) && !ignoretalk) {
			} else if ((fr->frametype == AST_FRAME_VOICE) && ( ast_format_cap_iscompatible(cap, &fr->subclass.format)) && !ignoretalk) {
				int totalsilence;
				int ms;
				res = ast_dsp_silence(dsp, fr, &totalsilence);
				if (res && (totalsilence > sildur)) {
					/* We've been quiet a little while */
					if (notsilent) {
						/* We had heard some talking */
						gettimeofday(&end, NULL);
						ms = (end.tv_sec - start.tv_sec) * 1000;
						ms += (end.tv_usec - start.tv_usec) / 1000;
						ms -= sildur;
						if (ms < 0)
							ms = 0;
						if ((ms > mindur) && ((maxdur < 0) || (ms < maxdur))) {
							char ms_str[10];
							ast_log(LOG_DEBUG, "Found qualified token of %d ms\n", ms);
							ast_log(LOG_NOTICE, "Redirecting %s to talk extension\n", ast_channel_name(chan));

							/* Save detected talk time (in milliseconds) */ 
							sprintf(ms_str, "%d", ms);	
							pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str);

							if (ast_exists_extension(chan, ast_channel_context(chan), "talk", 1, ast_channel_caller(chan)->id.number.str)) {
// 								strncpy(ast_channel_exten(chan), "talk", sizeof(ast_channel_exten(chan)) - 1);
// 								chan->priority = 0;
								ast_channel_exten_set(chan, "talk");
								ast_channel_priority_set(chan, 0);
							} else
								ast_log(LOG_WARNING, "Talk detected, but no talk extension\n");
							res = 0;
							ast_frfree(fr);
							break;
						} else
							ast_log(LOG_DEBUG, "Found unqualified token of %d ms\n", ms);
						notsilent = 0;
					}
				} else {
					if (!notsilent) {
						/* Heard some audio, mark the begining of the token */
						gettimeofday(&start, NULL);
						ast_log(LOG_DEBUG, "Start of voice token!\n");
						notsilent = 1;
					}
				}						
			}
			ast_frfree(fr);
		}
	} else
		ast_log(LOG_WARNING, "Could not answer channel '%s'\n", ast_channel_name(chan));
	
	if (res > -1) {
		if (origrformat && ast_set_read_format(chan, origrformat)) {
			ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n", 
				ast_channel_name(chan), ast_getformatname(origrformat));
		}
	}
	
	if (dsp)
		ast_dsp_free(dsp);
	
	//	LOCAL_USER_REMOVE(u);
	ast_format_cap_destroy(cap);
	return res;
}
Пример #3
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;
}
Пример #4
0
static int container_test1_helper(struct ast_format_cap *cap1, struct ast_format_cap *cap2, struct ast_test *test)
{

	int res = AST_TEST_PASS;
	struct ast_format_cap *cap_joint = NULL;
	struct ast_format tmpformat;

	if (ast_format_attr_reg_interface(&test_interface)) {
		ast_test_status_update(test, "test_interface failed to register.\n");
		ast_format_cap_destroy(cap1);
		ast_format_cap_destroy(cap2);
		return AST_TEST_FAIL;
	}

	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0));
	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0));
	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_G722, 0));
	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_ALAW, 0));
	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_H264, 0));
	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_H263, 0));
	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_T140, 0));
	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_JPEG, 0));
	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1,
			TEST_ATTR_KEY_STRING, "testing caps hooray",
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_32KHZ,
			AST_FORMAT_ATTR_END));

	/* Test is compatible */
	if (!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_ALAW, 0)) ||
		!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0)) ||
		!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0)) ||
		!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_H264, 0)) ||
		!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_JPEG, 0)) ||
		!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_T140, 0))) {
		ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 1.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}

	/* Test things that are not compatible */
	if (ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_SPEEX, 0)) ||
		ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_SPEEX16, 0)) ||
		ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_H261, 0))) {
		ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 2.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}

	/* Test compatiblity with format with attributes. */
	if (!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1,
			TEST_ATTR_KEY_STRING, "testing caps hooray",
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ,
			AST_FORMAT_ATTR_END))) {

		ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 3.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	if (!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
			AST_FORMAT_ATTR_END))) {

		ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 4.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	if (ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_48KHZ, /* 48khz was not compatible, so this should fail iscompatible check */
			AST_FORMAT_ATTR_END))) {

		ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 5.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}

	/* Lets start testing the functions that compare ast_format_cap objects.
	 * Genreate the cap2 object to contain some similar formats as cap1
	 * and some different formats as well. */
	ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0));
	ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0));
	ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_SIREN7, 0));
	ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_H261, 0));
	ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_T140, 0));
	ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1,
			TEST_ATTR_KEY_STRING, "testing caps hooray",
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_12KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_32KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_48KHZ,
			AST_FORMAT_ATTR_END));


	/* find joint formats between cap1 and cap2 */
	cap_joint = ast_format_cap_joint(cap1, cap2);

	if (!cap_joint) {
		ast_test_status_update(test, "failed to create joint capabilities correctly.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	/* determine if cap_joint is what we think it should be */
	if (!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0)) ||
		!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0)) ||
		!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_T140, 0)) ||
		!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1,
			TEST_ATTR_KEY_STRING, "testing caps hooray",
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ,
			AST_FORMAT_ATTR_END))) {

		ast_test_status_update(test, "ast cap_joint failed to properly detect compatibility test 1.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	/* make sure joint cap does not have formats that should not be there */
	if (ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_SIREN7, 0)) ||
		ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1,
			TEST_ATTR_KEY_STRING, "testing caps hooray",
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_48KHZ,
			AST_FORMAT_ATTR_END))) {

		ast_test_status_update(test, "ast cap_joint failed to properly detect compatibility test 1.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}

	/* Lets test removing a capability */
	if (ast_format_cap_remove(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_T140, 0))) {
		ast_test_status_update(test, "ast_format_cap_remove failed. \n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	/* Lets make sure what we just removed does not still exist */
	if (ast_format_cap_iscompatible(cap_joint, &tmpformat)) {
		ast_test_status_update(test, "ast_format_cap_remove failed 2. \n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	/* Lets test removing a capability by id.*/
	if (ast_format_cap_remove_byid(cap_joint, AST_FORMAT_GSM)) {
		ast_test_status_update(test, "ast_format_cap_remove failed 3. \n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	/* Lets make sure what we just removed does not still exist */
	if (ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0))) {
		ast_test_status_update(test, "ast_format_cap_remove failed 4. \n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}

	/* lets test getting joint formats by type */
	ast_format_cap_destroy(cap_joint);
	if (!(cap_joint = ast_format_cap_get_type(cap1, AST_FORMAT_TYPE_VIDEO))) {
		ast_test_status_update(test, "ast_format_cap_get_type failed.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	/* lets make sure our joint capability structure has what we expect */
	if (!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_H264, 0)) ||
		!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_H263, 0))) {
		ast_test_status_update(test, "get_type failed 2.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	/* now make sure joint does not have anything but video */
	if (ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_ALAW, 0)) ||
		ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0)) ||
		ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0)) ||
		ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_JPEG, 0)) ||
		ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_T140, 0))) {
		ast_test_status_update(test, "get_type failed 3.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}

	/* now lets remove everythign from cap_joint */
	ast_format_cap_remove_all(cap_joint);
	if (!ast_format_cap_is_empty(cap_joint)) {
		ast_test_status_update(test, "failed to remove all\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}

	/* now lets add all by type */
	ast_format_cap_add_all_by_type(cap_joint, AST_FORMAT_TYPE_AUDIO);
	if (ast_format_cap_is_empty(cap_joint)) {
			ast_test_status_update(test, "failed to add all by type AUDIO\n");
			res = AST_TEST_FAIL;
	}
	ast_format_cap_iter_start(cap_joint);
	while (!(ast_format_cap_iter_next(cap_joint, &tmpformat))) {
		if (AST_FORMAT_GET_TYPE(tmpformat.id) != AST_FORMAT_TYPE_AUDIO) {
			ast_test_status_update(test, "failed to add all by type AUDIO\n");
			res = AST_TEST_FAIL;
			ast_format_cap_iter_end(cap_joint);
			goto test3_cleanup;
		}
	}
	ast_format_cap_iter_end(cap_joint);

	/* test append */
	ast_format_cap_append(cap_joint, cap1);
	ast_format_cap_iter_start(cap1);
	while (!(ast_format_cap_iter_next(cap1, &tmpformat))) {
		if (!ast_format_cap_iscompatible(cap_joint, &tmpformat)) {
			ast_test_status_update(test, "failed to append format capabilities.\n");
			res = AST_TEST_FAIL;
			ast_format_cap_iter_end(cap1);
			goto test3_cleanup;
		}
	}
	ast_format_cap_iter_end(cap1);

	/* test copy */
	cap1 = ast_format_cap_destroy(cap1);
	cap1 = ast_format_cap_dup(cap_joint);
	if (!ast_format_cap_identical(cap_joint, cap1)) {
			ast_test_status_update(test, "failed to copy capabilities\n");
			res = AST_TEST_FAIL;
			goto test3_cleanup;
	}

	/* test remove by type */
	ast_format_cap_remove_bytype(cap_joint, AST_FORMAT_TYPE_AUDIO);
	if (ast_format_cap_has_type(cap_joint, AST_FORMAT_TYPE_AUDIO)) {
		ast_test_status_update(test, "failed to remove all by type audio\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	if (!ast_format_cap_has_type(cap_joint, AST_FORMAT_TYPE_TEXT)) { /* it should still have text */
		ast_test_status_update(test, "failed to remove all by type audio\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	ast_format_cap_iter_start(cap_joint);
	while (!(ast_format_cap_iter_next(cap_joint, &tmpformat))) {
		if (AST_FORMAT_GET_TYPE(tmpformat.id) == AST_FORMAT_TYPE_AUDIO) {
			ast_test_status_update(test, "failed to remove all by type audio\n");
			res = AST_TEST_FAIL;
			ast_format_cap_iter_end(cap_joint);
			goto test3_cleanup;
		}
	}
	ast_format_cap_iter_end(cap_joint);

	/* test add all */
	ast_format_cap_remove_all(cap_joint);
	ast_format_cap_add_all(cap_joint);
	{
		int video = 0, audio = 0, text = 0, image = 0;
		ast_format_cap_iter_start(cap_joint);
		while (!(ast_format_cap_iter_next(cap_joint, &tmpformat))) {
			switch (AST_FORMAT_GET_TYPE(tmpformat.id)) {
			case AST_FORMAT_TYPE_AUDIO:
				audio++;
				break;
			case AST_FORMAT_TYPE_VIDEO:
				video++;
				break;
			case AST_FORMAT_TYPE_TEXT:
				text++;
				break;
			case AST_FORMAT_TYPE_IMAGE:
				image++;
				break;
			}
		}
		ast_format_cap_iter_end(cap_joint);
		if (!video || !audio || !text || !image) {
			ast_test_status_update(test, "failed to add all\n");
			res = AST_TEST_FAIL;
			goto test3_cleanup;
		}
	}

	/* test copy2 */
	ast_format_cap_copy(cap2, cap_joint);
	if (!ast_format_cap_identical(cap2, cap_joint)) {
		ast_test_status_update(test, "ast_format_cap_copy failed\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}

test3_cleanup:
	ast_format_cap_destroy(cap1);
	ast_format_cap_destroy(cap2);
	ast_format_cap_destroy(cap_joint);

	/* unregister interface */
	if (ast_format_attr_unreg_interface(&test_interface)) {
		ast_test_status_update(test, "test_interface failed to unregister.\n");
		res = AST_TEST_FAIL;
	}

	return res;
}
Пример #5
0
static int native_rtp_bridge_compatible_check(struct ast_bridge *bridge, struct ast_bridge_channel *bc0, struct ast_bridge_channel *bc1)
{
	enum ast_rtp_glue_result native_type;
	struct ast_rtp_glue *glue0;
	struct ast_rtp_glue *glue1;
	RAII_VAR(struct ast_rtp_instance *, instance0, NULL, ao2_cleanup);
	RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ao2_cleanup);
	RAII_VAR(struct ast_rtp_instance *, vinstance0, NULL, ao2_cleanup);
	RAII_VAR(struct ast_rtp_instance *, vinstance1, NULL, ao2_cleanup);
	RAII_VAR(struct ast_format_cap *, cap0, NULL, ao2_cleanup);
	RAII_VAR(struct ast_format_cap *, cap1, NULL, ao2_cleanup);
	int read_ptime0;
	int read_ptime1;
	int write_ptime0;
	int write_ptime1;

	if (!native_rtp_bridge_capable(bc0->chan)) {
		ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has features which prevent it\n",
			bridge->uniqueid, ast_channel_name(bc0->chan));
		return 0;
	}

	if (!native_rtp_bridge_capable(bc1->chan)) {
		ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has features which prevent it\n",
			bridge->uniqueid, ast_channel_name(bc1->chan));
		return 0;
	}

	native_type = native_rtp_bridge_get(bc0->chan, bc1->chan, &glue0, &glue1,
		&instance0, &instance1, &vinstance0, &vinstance1);
	if (native_type == AST_RTP_GLUE_RESULT_FORBID) {
		ast_debug(1, "Bridge '%s' can not use native RTP bridge as it was forbidden while getting details\n",
			bridge->uniqueid);
		return 0;
	}

	if (ao2_container_count(bc0->features->dtmf_hooks)
		&& ast_rtp_instance_dtmf_mode_get(instance0)) {
		ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has DTMF hooks\n",
			bridge->uniqueid, ast_channel_name(bc0->chan));
		return 0;
	}

	if (ao2_container_count(bc1->features->dtmf_hooks)
		&& ast_rtp_instance_dtmf_mode_get(instance1)) {
		ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has DTMF hooks\n",
			bridge->uniqueid, ast_channel_name(bc1->chan));
		return 0;
	}

	if (native_type == AST_RTP_GLUE_RESULT_LOCAL
		&& (ast_rtp_instance_get_engine(instance0)->local_bridge
			!= ast_rtp_instance_get_engine(instance1)->local_bridge
			|| (ast_rtp_instance_get_engine(instance0)->dtmf_compatible
				&& !ast_rtp_instance_get_engine(instance0)->dtmf_compatible(bc0->chan,
					instance0, bc1->chan, instance1)))) {
		ast_debug(1, "Bridge '%s' can not use local native RTP bridge as local bridge or DTMF is not compatible\n",
			bridge->uniqueid);
		return 0;
	}

	cap0 = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
	cap1 = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
	if (!cap0 || !cap1) {
		return 0;
	}

	/* Make sure that codecs match */
	if (glue0->get_codec) {
		glue0->get_codec(bc0->chan, cap0);
	}
	if (glue1->get_codec) {
		glue1->get_codec(bc1->chan, cap1);
	}
	if (ast_format_cap_count(cap0) != 0
		&& ast_format_cap_count(cap1) != 0
		&& !ast_format_cap_iscompatible(cap0, cap1)) {
		struct ast_str *codec_buf0 = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
		struct ast_str *codec_buf1 = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);

		ast_debug(1, "Bridge '%s': Channel codec0 = %s is not codec1 = %s, cannot native bridge in RTP.\n",
			bridge->uniqueid,
			ast_format_cap_get_names(cap0, &codec_buf0),
			ast_format_cap_get_names(cap1, &codec_buf1));
		return 0;
	}

	read_ptime0 = ast_format_cap_get_format_framing(cap0, ast_channel_rawreadformat(bc0->chan));
	read_ptime1 = ast_format_cap_get_format_framing(cap1, ast_channel_rawreadformat(bc1->chan));
	write_ptime0 = ast_format_cap_get_format_framing(cap0, ast_channel_rawwriteformat(bc0->chan));
	write_ptime1 = ast_format_cap_get_format_framing(cap1, ast_channel_rawwriteformat(bc1->chan));

	if (read_ptime0 != write_ptime1 || read_ptime1 != write_ptime0) {
		ast_debug(1, "Bridge '%s': Packetization differs between RTP streams (%d != %d or %d != %d). Cannot native bridge in RTP\n",
			bridge->uniqueid,
			read_ptime0, write_ptime1, read_ptime1, write_ptime0);
		return 0;
	}

	return 1;
}