예제 #1
0
static void cepstral_text_param_tts(switch_speech_handle_t *sh, char *param, const char *val)
{
	cepstral_t *cepstral;

	cepstral = sh->private_info;
	assert(cepstral != NULL);

	if (!strcasecmp(param, "voice")) {
		const char *voice_name = val;
		if (!strcasecmp(voice_name, "next")) {
			if ((cepstral->voice = swift_port_find_next_voice(cepstral->port))) {
				if (SWIFT_FAILED(swift_port_set_voice(cepstral->port, cepstral->voice))) {
					cepstral->done = cepstral->done_gen = 1;
					return;
				}
				voice_name = swift_voice_get_attribute(cepstral->voice, "name");
			} else {
				voice_name = NULL;
			}
		} else {
			if (voice_name && SWIFT_FAILED(swift_port_set_voice_by_name(cepstral->port, voice_name))) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid voice %s!\n", voice_name);
				voice_name = NULL;
			}
		}

		if (!voice_name) {
			/* Find the first voice on the system */
			if ((cepstral->voice = swift_port_find_first_voice(cepstral->port, NULL, NULL)) == NULL) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to find any voices!\n");
				cepstral->done = cepstral->done_gen = 1;
				return;
			}

			/* Set the voice found by find_first_voice() as the port's current voice */
			if (SWIFT_FAILED(swift_port_set_voice(cepstral->port, cepstral->voice))) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to set voice.\n");
				cepstral->done = cepstral->done_gen = 1;
				return;
			}

			voice_name = swift_voice_get_attribute(cepstral->voice, "name");
		}

		if (voice_name) {
			switch_copy_string(sh->voice, voice_name, sizeof(sh->voice));
		}

		return;
	}

	swift_port_set_param_string(cepstral->port, param, val, NULL);
}
예제 #2
0
/** Swift engine callback */
static swift_result_t mrcp_swift_write_audio(swift_event *event, swift_event_t type, void *udata)
{
	void *buf;
	int len;
	mrcp_swift_channel_t *synth_channel = udata;
	swift_event_t rv = SWIFT_SUCCESS;

	if(type & SWIFT_EVENT_END) {
		apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Swift Engine: Write End-of-Speech Event");
		mpf_buffer_event_write(synth_channel->audio_buffer,MEDIA_FRAME_TYPE_EVENT);
		return rv;
	}

	rv = swift_event_get_audio(event, &buf, &len);
	if(!SWIFT_FAILED(rv)) {
#if 0
		/* Get the event times */
		float time_start, time_len; 
		swift_event_get_times(event, &time_start, &time_len);
		apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Swift Engine: Write Audio [%d | %0.4f | %0.4f]",len, time_start, time_len);
#endif
		mpf_buffer_audio_write(synth_channel->audio_buffer,buf,len);
	}

	return rv;
}
예제 #3
0
/** Set Swift port param */
static apt_bool_t mrcp_swift_channel_param_set(mrcp_swift_channel_t *synth_channel, const char *name, swift_val *val)
{
	swift_result_t res;
	if(SWIFT_FAILED(res = swift_port_set_param(synth_channel->port,name,val,synth_channel->tts_stream)) ) {
		const char *error_string = swift_strerror(res);
		apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Swift Param %s: %s",name,error_string);
		return FALSE;
	}
	return TRUE;
}
예제 #4
0
/* This callback caches the audio in the buffer */
static swift_result_t write_audio(swift_event * event, swift_event_t type, void *udata)
{
	cepstral_t *cepstral;
	swift_event_t rv = SWIFT_SUCCESS;
	void *buf = NULL;
	int len = 0, i = 0;

	cepstral = udata;
	assert(cepstral != NULL);

	if (!cepstral->port || cepstral->done || cepstral->done_gen) {
		return SWIFT_UNKNOWN_ERROR;
	}

	/* Only proceed when we have success */
	if (!SWIFT_FAILED((rv = swift_event_get_audio(event, &buf, &len)))) {
		while (!cepstral->done) {
			switch_mutex_lock(cepstral->audio_lock);
			if (switch_buffer_write(cepstral->audio_buffer, buf, len) > 0) {
				switch_mutex_unlock(cepstral->audio_lock);
				break;
			}
			switch_mutex_unlock(cepstral->audio_lock);
			if (!cepstral->done) {
				for (i = 0; i < 10; i++) {
					switch_yield(10000);
					if (cepstral->done) {
						break;
					}
				}
			}

		}
	} else {
		cepstral->done = 1;
	}

	if (cepstral->done) {
		rv = SWIFT_UNKNOWN_ERROR;
	}

	return rv;
}
예제 #5
0
/** Set voice matching specified criteria */
static apt_bool_t mrcp_swift_channel_voice_set(mrcp_swift_channel_t *synth_channel, mrcp_message_t *message)
{
	mrcp_synth_header_t *synth_header = mrcp_resource_header_get(message);
	char search_criteria[1024];
	int offset = 0;
	swift_voice *voice;
	swift_result_t res;

	if(!synth_header) {
		/* no params to set */
		return TRUE;
	}

	if(mrcp_resource_header_property_check(message,SYNTHESIZER_HEADER_VOICE_NAME) == TRUE) {
		offset += search_criteria_delimiter_add(search_criteria+offset,sizeof(search_criteria)-offset,(offset == 0));
		offset += apr_snprintf(search_criteria+offset,sizeof(search_criteria)-offset,"speaker/name=%s",synth_header->voice_param.name.buf);
	}
	if(mrcp_resource_header_property_check(message,SYNTHESIZER_HEADER_VOICE_GENDER) == TRUE) {
		switch(synth_header->voice_param.gender) {
			case VOICE_GENDER_MALE:
				offset += search_criteria_delimiter_add(search_criteria+offset,sizeof(search_criteria)-offset,offset == 0);
				offset += apr_snprintf(search_criteria+offset,sizeof(search_criteria)-offset,"speaker/gender=male");
				break;
			case VOICE_GENDER_FEMALE:
				offset += search_criteria_delimiter_add(search_criteria+offset,sizeof(search_criteria)-offset,offset == 0);
				offset += apr_snprintf(search_criteria+offset,sizeof(search_criteria)-offset,"speaker/gender=female");
				break;
			default:
				break;
		}
	}
	if(mrcp_resource_header_property_check(message,SYNTHESIZER_HEADER_VOICE_AGE) == TRUE) {
		offset += search_criteria_delimiter_add(search_criteria+offset,sizeof(search_criteria)-offset,offset == 0);
		offset += apr_snprintf(search_criteria+offset,sizeof(search_criteria)-offset,"speaker/age=%d",synth_header->voice_param.age);
	}
	if(mrcp_resource_header_property_check(message,SYNTHESIZER_HEADER_SPEECH_LANGUAGE) == TRUE) {
		const char *swift_lang_name = NULL;
		if(swift_speech_language_table) {
			swift_lang_name = apr_table_get(swift_speech_language_table,synth_header->speech_language.buf);
		}
		if(!swift_lang_name) {
			swift_lang_name = synth_header->speech_language.buf;
		}
		offset += search_criteria_delimiter_add(search_criteria+offset,sizeof(search_criteria)-offset,offset == 0);
		offset += apr_snprintf(search_criteria+offset,sizeof(search_criteria)-offset,"language/name=%s",swift_lang_name);
	}

	if(offset > 0) {
		apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Find Voices Matching the Criteria [%s]",search_criteria);
		if((voice = swift_port_find_first_voice(synth_channel->port,search_criteria,NULL)) == NULL) {
			apt_log(APT_LOG_MARK,APT_PRIO_INFO,"No Swift Voice Available Matching the Criteria [%s]",search_criteria);
			voice = swift_port_find_first_voice(synth_channel->port,NULL,NULL);
		}
		if(SWIFT_FAILED(res = swift_port_set_voice(synth_channel->port,voice)) ) {
			const char *error_string = swift_strerror(res);
			apt_log(APT_LOG_MARK,APT_PRIO_INFO,error_string);
			return FALSE;
		} 
	}
	return TRUE;
}
예제 #6
0
static int app_exec(struct ast_channel *chan, void *data)
{
	int res = 0, argc = 0, max_digits = 0, timeout = 0, alreadyran = 0, old_writeformat = 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 myframe {
		struct ast_frame f;
		unsigned char offset[AST_FRIENDLY_OFFSET];
		unsigned char frdata[framesize];
	} myf;

	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);
	old_writeformat = chan->writeformat;

	if (ast_set_write_format(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;
				myf.f.subclass = AST_FORMAT_ULAW;
				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 originDTMF = f->subclass;
					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", originDTMF, rc);
					} else {
						sprintf(results, "%c", originDTMF);
					}

					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->cid.cid_num)) {
				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 && old_writeformat) {
		ast_set_write_format(chan, old_writeformat);
	}

	ast_module_user_remove(u);
	return res;
}
예제 #7
0
static swift_result_t swift_cb(swift_event *event, swift_event_t type, void *udata)
{
	void *buf;
	int len, spacefree;
	unsigned long sleepfor;
	swift_event_t rv = SWIFT_SUCCESS;
	struct stuff *ps = udata;

	if (type == SWIFT_EVENT_AUDIO) {
		rv = swift_event_get_audio(event, &buf, &len);

		if (!SWIFT_FAILED(rv) && len > 0) {
			ast_log(LOG_DEBUG, "audio callback\n");
			ASTOBJ_WRLOCK(ps);

			/* Sleep while waiting for some queue space to become available */
			while (len + ps->qc > cfg_buffer_size && !ps->immediate_exit) {
				/* Each byte is 125us of time, so assume queue space will become available
				   at that rate and guess when we'll have enough space available.
				   + another (125 usec/sample * framesize samples) (1 frame) for fudge */
				sleepfor = ((unsigned long)(len - (cfg_buffer_size - ps->qc)) * 125UL) + (125UL * (unsigned long)framesize);
				/* ast_log(LOG_DEBUG, "generator: %d bytes to write but only %d space avail, sleeping %ldus\n", len, cfg_buffer_size - ps->qc, sleepfor); */
				ASTOBJ_UNLOCK(ps);
				usleep(sleepfor);
				ASTOBJ_WRLOCK(ps);
			}
			if (ps->immediate_exit) {
				ASTOBJ_UNLOCK(ps);
				return SWIFT_SUCCESS;
			}

			spacefree = cfg_buffer_size - ((uintptr_t) ps->pq_w - (uintptr_t)ps->q);

			if (len > spacefree) {
				ast_log(LOG_DEBUG, "audio fancy write; %d bytes but only %d avail to end %d totalavail\n", len, spacefree, cfg_buffer_size - ps->qc);

				/* write #1 to end of mem */
				memcpy(ps->pq_w, buf, spacefree);
				ps->pq_w = ps->q;
				ps->qc += spacefree;

				/* write #2 and beg of mem */
				memcpy(ps->pq_w, buf + spacefree, len - spacefree);
				ps->pq_w += len - spacefree;
				ps->qc += len - spacefree;
			} else {
				ast_log(LOG_DEBUG, "audio easy write, %d avail to end %d totalavail\n", spacefree, cfg_buffer_size - ps->qc);
				memcpy(ps->pq_w, buf, len);
				ps->pq_w += len;
				ps->qc += len;
			}

			ASTOBJ_UNLOCK(ps);
		} else {
			ast_log(LOG_DEBUG, "got audio callback but get_audio call failed\n");
		}
	} else if (type == SWIFT_EVENT_END) {
		ast_log(LOG_DEBUG, "got END callback; done generating audio\n");
		ASTOBJ_WRLOCK(ps);
		ps->generating_done = 1;
		ASTOBJ_UNLOCK(ps);
	} else {
		ast_log(LOG_DEBUG, "UNKNOWN callback\n");
	}
	return rv;
}
예제 #8
0
static switch_status_t cepstral_speech_open(switch_speech_handle_t *sh, const char *voice_name, int rate, switch_speech_flag_t *flags)
{
	cepstral_t *cepstral = switch_core_alloc(sh->memory_pool, sizeof(*cepstral));
	char srate[25];

	if (!cepstral) {
		return SWITCH_STATUS_MEMERR;
	}

	if (switch_buffer_create_dynamic(&cepstral->audio_buffer, MY_BLOCK_SIZE, MY_BUF_LEN, 0) != SWITCH_STATUS_SUCCESS) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Write Buffer Failed!\n");
		return SWITCH_STATUS_MEMERR;
	}


	switch_mutex_init(&cepstral->audio_lock, SWITCH_MUTEX_NESTED, sh->memory_pool);


	cepstral->params = swift_params_new(NULL);
	swift_params_set_string(cepstral->params, "audio/encoding", "pcm16");
	switch_snprintf(srate, sizeof(srate), "%d", rate);
	swift_params_set_string(cepstral->params, "audio/sampling-rate", srate);


	/* Open a Swift Port through which to make TTS calls */
	if (!(cepstral->port = swift_port_open(engine, cepstral->params))) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to open Swift Port.\n");
		goto all_done;
	}


	if (voice_name && SWIFT_FAILED(swift_port_set_voice_by_name(cepstral->port, voice_name))) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid voice %s!\n", voice_name);
		voice_name = NULL;
	}

	if (zstr(voice_name)) {
		/* Find the first voice on the system */
		if ((cepstral->voice = swift_port_find_first_voice(cepstral->port, NULL, NULL)) == NULL) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to find any voices!\n");
			goto all_done;
		}

		/* Set the voice found by find_first_voice() as the port's current voice */
		if (SWIFT_FAILED(swift_port_set_voice(cepstral->port, cepstral->voice))) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to set voice.\n");
			goto all_done;
		}

		voice_name = (char *) swift_voice_get_attribute(cepstral->voice, "name");
	}

	if (voice_name) {
		switch_copy_string(sh->voice, voice_name, sizeof(sh->voice));
	}

	swift_port_set_callback(cepstral->port, &write_audio, SWIFT_EVENT_AUDIO, cepstral);

	sh->private_info = cepstral;
	return SWITCH_STATUS_SUCCESS;

  all_done:
	return SWITCH_STATUS_FALSE;
}