commit e8f60761378fe392d80e89d0e3481316119e9809

Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Jun 30 14:44:09 2009 +0000

    Further build and install integration
    
    git-svn-id: https://unimrcp.googlecode.com/svn/trunk@1030 f001bc3a-424a-0410-80a0-a715b8f413a8

commit 5b410e0dfc1852ee5c0d56d64b326d5130aed18a
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Jun 30 13:24:27 2009 +0000

    Added utility project (preparesphinx) to copy the stuff pocketsphinx requires to run
    
    git-svn-id: https://unimrcp.googlecode.com/svn/trunk@1029 f001bc3a-424a-0410-80a0-a715b8f413a8

commit 2457575de160b378affdfa7a37cac1282d0024ca
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Jun 30 13:18:59 2009 +0000

    Added a few more comments in config file
    
    git-svn-id: https://unimrcp.googlecode.com/svn/trunk@1028 f001bc3a-424a-0410-80a0-a715b8f413a8

commit ffc40b15b409a79bdea286898ad1e8694fc1623c
Author: garmt.noname@gmail.com <garmt.noname@gmail.com@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Jun 30 10:38:54 2009 +0000

    Added resampling to 8kHz so that it works with freeswitch (specify only L16/96/8000 codec in profile of media_engine/rtpfactory).
    Changed logging to DEBUG level rather than INFO.
    Added channel_guard for stop response.
    
    
    git-svn-id: https://unimrcp.googlecode.com/svn/trunk@1027 f001bc3a-424a-0410-80a0-a715b8f413a8

commit d11439611186b46f1bfabc036b7e5d76f33f8b0e
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Jun 29 19:46:54 2009 +0000

    Added entries for PocketSphinx (mrcppocketsphinx) and Flite (mrcpflite) plugins into unimrcpserver.xml (disabled by default)
    
    git-svn-id: https://unimrcp.googlecode.com/svn/trunk@1026 f001bc3a-424a-0410-80a0-a715b8f413a8

commit 63bc73426ba4efdf648a28cd3c1ff1daaef5bb49
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Jun 29 15:04:01 2009 +0000

    Added enumeration of pocketsphinx models (narrowband, wideband), supported wideband either
    
    git-svn-id: https://unimrcp.googlecode.com/svn/trunk@1025 f001bc3a-424a-0410-80a0-a715b8f413a8

commit d11439611186b46f1bfabc036b7e5d76f33f8b0e
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Jun 29 19:46:54 2009 +0000

    Added entries for PocketSphinx (mrcppocketsphinx) and Flite (mrcpflite) plugins into unimrcpserver.xml (disabled by default)

    git-svn-id: https://unimrcp.googlecode.com/svn/trunk@1026 f001bc3a-424a-0410-80a0-a715b8f413a8

commit 63bc73426ba4efdf648a28cd3c1ff1daaef5bb49
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Jun 29 15:04:01 2009 +0000

    Added enumeration of pocketsphinx models (narrowband, wideband), supported wideband either

    git-svn-id: https://unimrcp.googlecode.com/svn/trunk@1025 f001bc3a-424a-0410-80a0-a715b8f413a8

commit 04970484e4357e2a1c3c4385840640caada33468
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Jun 29 13:21:35 2009 +0000

    Removed engine->guard, as all relevant calls are made within the context of the same thread

    git-svn-id: https://unimrcp.googlecode.com/svn/trunk@1024 f001bc3a-424a-0410-80a0-a715b8f413a8

commit 9bac2f3abdcfea5397aca4b86e209af090631e7a
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Jun 29 13:15:30 2009 +0000

    Initialized 16kHz codec descriptor for flite channel, since available flite voice are in 16kHz.

    git-svn-id: https://unimrcp.googlecode.com/svn/trunk@1023 f001bc3a-424a-0410-80a0-a715b8f413a8

commit 4e902eb985b433416723f15646d3e99d385d18cb
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Jun 28 20:05:22 2009 +0000

    Do not create bridge if resampling is required.
    Several sampling rates are supported, but there is no resampling yet.

    git-svn-id: https://unimrcp.googlecode.com/svn/trunk@1022 f001bc3a-424a-0410-80a0-a715b8f413a8

commit 6d35b1246a7061e4c8f3f608bb17e146870d63bd
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Jun 28 18:14:25 2009 +0000

    Added makefile target to install pocketsphinx.xml with make install

    git-svn-id: https://unimrcp.googlecode.com/svn/trunk@1021 f001bc3a-424a-0410-80a0-a715b8f413a8

commit c2b75c89d57c02bd8d4360aebcb7406ecbf90eb0
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Jun 28 18:10:01 2009 +0000

    Set svn props (eol:native)

    git-svn-id: https://unimrcp.googlecode.com/svn/trunk@1020 f001bc3a-424a-0410-80a0-a715b8f413a8

commit dd91ebea823dd2169e8c30f0cfe87fa199e1a0c2
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Jun 28 17:46:46 2009 +0000

    Loaded pocketsphinx's properties from config file

    git-svn-id: https://unimrcp.googlecode.com/svn/trunk@1019 f001bc3a-424a-0410-80a0-a715b8f413a8

commit 2ba91890593d7a64136e675bb937efd9a2542cc7
Author: garmt.noname@gmail.com <garmt.noname@gmail.com@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Jun 28 12:29:54 2009 +0000

    Removed session tasks, most channel tasks, flite voices are no longer global

    git-svn-id: https://unimrcp.googlecode.com/svn/trunk@1018 f001bc3a-424a-0410-80a0-a715b8f413a8

commit 0d739127f9267b3ad871d1a53a863802f101a6b5
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Jun 27 09:15:20 2009 +0000

    Implemented save_waveform, utterance will be saved in the filesystem

    git-svn-id: https://unimrcp.googlecode.com/svn/trunk@1017 f001bc3a-424a-0410-80a0-a715b8f413a8

commit 4ffd282ddf54ad861d73f36567ad201d135feff5
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Jun 27 08:24:19 2009 +0000

    Set 2 digits precision (digits after the decimal point) while generating float type values (Issue-35).

    git-svn-id: https://unimrcp.googlecode.com/svn/trunk@1016 f001bc3a-424a-0410-80a0-a715b8f413a8

commit 90446f5e6ece40e91fd5b340a45e6773e4e80a0f
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Jun 27 07:42:52 2009 +0000

    Set noinut and recognition timeouts if specified in RECOGNIZE request, reset input timer on partial match

    git-svn-id: https://unimrcp.googlecode.com/svn/trunk@1015 f001bc3a-424a-0410-80a0-a715b8f413a8



git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@14104 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Brian West
2009-07-02 00:54:48 +00:00
parent 03b73eb46e
commit 6d8d1a09d0
15 changed files with 776 additions and 453 deletions

View File

@@ -35,14 +35,15 @@
#include "mrcp_generic_header.h"
#include "mrcp_message.h"
#include "mpf_activity_detector.h"
#include "pocketsphinx_properties.h"
#include "apt_log.h"
#define POCKETSPHINX_CONFFILE_NAME "pocketsphinx.xml"
#define RECOGNIZER_SIDRES(recognizer) (recognizer)->channel->id.buf, "pocketsphinx"
typedef struct pocketsphinx_engine_t pocketsphinx_engine_t;
typedef struct pocketsphinx_recognizer_t pocketsphinx_recognizer_t;
typedef struct pocketsphinx_properties_t pocketsphinx_properties_t;
/** Methods of recognition engine */
static apt_bool_t pocketsphinx_engine_destroy(mrcp_resource_engine_t *engine);
@@ -86,23 +87,14 @@ static const mpf_audio_stream_vtable_t audio_stream_vtable = {
/** Pocketsphinx engine (engine is an aggregation of recognizers) */
struct pocketsphinx_engine_t {
mrcp_resource_engine_t *base;
};
/** Pocketsphinx properties */
struct pocketsphinx_properties_t {
const char *dictionary;
const char *model_8k;
const char *model_16k;
apr_size_t noinput_timeout;
apr_size_t recognition_timeout;
apr_size_t partial_result_timeout;
/* Resource engine base */
mrcp_resource_engine_t *base;
/** Properties loaded from config file */
pocketsphinx_properties_t properties;
};
/** Pocketsphinx channel (recognizer) */
struct pocketsphinx_recognizer_t {
/** Back pointer to engine */
pocketsphinx_engine_t *engine;
/** Engine channel base */
mrcp_engine_channel_t *channel;
@@ -110,12 +102,12 @@ struct pocketsphinx_recognizer_t {
ps_decoder_t *decoder;
/** Configuration */
cmd_ln_t *config;
/** Properties (to be loaded from config file) */
/** Recognizer properties coppied from defualt engine properties */
pocketsphinx_properties_t properties;
/** Is input timer started */
apt_bool_t is_input_timer_on;
/** Noinput timeout */
apr_size_t noinput_timeout;
apr_size_t no_input_timeout;
/** Recognition timeout */
apr_size_t recognition_timeout;
/** Timeout elapsed since the last partial result checking */
@@ -126,6 +118,8 @@ struct pocketsphinx_recognizer_t {
const char *grammar_id;
/** Table of defined grammars (key=content-id, value=grammar-file-path) */
apr_table_t *grammar_table;
/** File to write waveform to if save_waveform is on */
apr_file_t *waveform;
/** Voice activity detector */
mpf_activity_detector_t *detector;
@@ -170,33 +164,42 @@ MRCP_PLUGIN_DECLARE(mrcp_resource_engine_t*) mrcp_plugin_create(apr_pool_t *pool
}
/** Destroy pocketsphinx engine */
static apt_bool_t pocketsphinx_engine_destroy(mrcp_resource_engine_t *engine)
static apt_bool_t pocketsphinx_engine_destroy(mrcp_resource_engine_t *resource_engine)
{
return TRUE;
}
/** Open pocketsphinx engine */
static apt_bool_t pocketsphinx_engine_open(mrcp_resource_engine_t *engine)
static apt_bool_t pocketsphinx_engine_open(mrcp_resource_engine_t *resource_engine)
{
pocketsphinx_engine_t *engine = resource_engine->obj;
const apt_dir_layout_t *dir_layout = resource_engine->dir_layout;
char *file_path = NULL;
apr_filepath_merge(&file_path,dir_layout->conf_dir_path,POCKETSPHINX_CONFFILE_NAME,0,resource_engine->pool);
/* load properties */
pocketsphinx_properties_load(&engine->properties,file_path,dir_layout,resource_engine->pool);
return TRUE;
}
/** Close pocketsphinx engine */
static apt_bool_t pocketsphinx_engine_close(mrcp_resource_engine_t *engine)
static apt_bool_t pocketsphinx_engine_close(mrcp_resource_engine_t *resource_engine)
{
return TRUE;
}
/** Create pocketsphinx recognizer */
static mrcp_engine_channel_t* pocketsphinx_engine_recognizer_create(mrcp_resource_engine_t *engine, apr_pool_t *pool)
static mrcp_engine_channel_t* pocketsphinx_engine_recognizer_create(mrcp_resource_engine_t *resource_engine, apr_pool_t *pool)
{
mrcp_engine_channel_t *channel;
mpf_codec_descriptor_t *codec_descriptor;
pocketsphinx_engine_t *engine = resource_engine->obj;
pocketsphinx_recognizer_t *recognizer = apr_palloc(pool,sizeof(pocketsphinx_recognizer_t));
// recognizer->engine = engine;
recognizer->decoder = NULL;
recognizer->config = NULL;
recognizer->is_input_timer_on = FALSE;
recognizer->noinput_timeout = 0;
recognizer->no_input_timeout = 0;
recognizer->recognition_timeout = 0;
recognizer->partial_result_timeout = 0;
recognizer->last_result = NULL;
@@ -211,10 +214,24 @@ static mrcp_engine_channel_t* pocketsphinx_engine_recognizer_create(mrcp_resourc
recognizer->close_requested = FALSE;
recognizer->grammar_id = NULL;
recognizer->grammar_table = apr_table_make(pool,1);
recognizer->waveform = NULL;
/* copy default properties loaded from config */
recognizer->properties = engine->properties;
codec_descriptor = (mpf_codec_descriptor_t *) apr_palloc(pool,sizeof(mpf_codec_descriptor_t));
mpf_codec_descriptor_init(codec_descriptor);
codec_descriptor->channel_count = 1;
codec_descriptor->payload_type = 96;
apt_string_set(&codec_descriptor->name,"LPCM");
codec_descriptor->sampling_rate = 8000;
if(recognizer->properties.preferred_model == POCKETSPHINX_MODEL_WIDEBAND) {
codec_descriptor->sampling_rate = 16000;
}
/* create engine channel base */
channel = mrcp_engine_sink_channel_create(
engine, /* resource engine */
resource_engine, /* resource engine */
&channel_vtable, /* virtual methods table of engine channel */
&audio_stream_vtable, /* virtual methods table of audio stream */
recognizer, /* object to associate */
@@ -295,33 +312,23 @@ static apt_bool_t pocketsphinx_recognizer_request_process(mrcp_engine_channel_t
return TRUE;
}
/** Load pocketsphinx properties [RECOG] */
static apt_bool_t pocketsphinx_properties_load(pocketsphinx_recognizer_t *recognizer)
{
mrcp_engine_channel_t *channel = recognizer->channel;
const apt_dir_layout_t *dir_layout = channel->engine->dir_layout;
pocketsphinx_properties_t *properties = &recognizer->properties;
properties->dictionary = apt_datadir_filepath_get(dir_layout,"pocketsphinx/default.dic",channel->pool);
properties->model_8k = apt_datadir_filepath_get(dir_layout,"pocketsphinx/communicator",channel->pool);
properties->model_16k = apt_datadir_filepath_get(dir_layout,"pocketsphinx/wsj1",channel->pool);
properties->noinput_timeout = 5000;
properties->recognition_timeout = 15000;
properties->partial_result_timeout = 100;
return TRUE;
}
/** Initialize pocketsphinx decoder [RECOG] */
static apt_bool_t pocketsphinx_decoder_init(pocketsphinx_recognizer_t *recognizer, const char *grammar)
{
apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Init Config "APT_SIDRES_FMT,RECOGNIZER_SIDRES(recognizer));
const char *model = recognizer->properties.model_8k;
const char *rate = "8000";
if(recognizer->properties.preferred_model == POCKETSPHINX_MODEL_WIDEBAND) {
model = recognizer->properties.model_16k;
rate = "16000";
}
apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Init Config rate [%s] dictionary [%s] "APT_SIDRES_FMT,
rate,
recognizer->properties.dictionary,
RECOGNIZER_SIDRES(recognizer));
recognizer->config = cmd_ln_init(recognizer->config, ps_args(), FALSE,
"-samprate", "8000",
"-hmm", recognizer->properties.model_8k,
"-samprate", rate,
"-hmm", model,
"-jsgf", grammar,
"-dict", recognizer->properties.dictionary,
"-frate", "50",
@@ -469,7 +476,7 @@ static apt_bool_t pocketsphinx_define_grammar(pocketsphinx_recognizer_t *recogni
return FALSE;
}
grammar_file_name = apr_psprintf(channel->pool,"pocketsphinx/%s-%s.gram",channel->id.buf,content_id);
grammar_file_name = apr_psprintf(channel->pool,"%s-%s.gram",channel->id.buf,content_id);
grammar_file_path = apt_datadir_filepath_get(dir_layout,grammar_file_name,channel->pool);
apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create Grammar File [%s] "APT_SIDRES_FMT,
@@ -519,6 +526,7 @@ static apt_bool_t pocketsphinx_define_grammar(pocketsphinx_recognizer_t *recogni
/** Process RECOGNIZE request [RECOG] */
static apt_bool_t pocketsphinx_recognize(pocketsphinx_recognizer_t *recognizer, mrcp_message_t *request, mrcp_message_t *response)
{
mrcp_engine_channel_t *channel = recognizer->channel;
mrcp_recog_header_t *request_recog_header;
mrcp_recog_header_t *response_recog_header = mrcp_resource_header_prepare(response);
if(!response_recog_header) {
@@ -541,16 +549,43 @@ static apt_bool_t pocketsphinx_recognize(pocketsphinx_recognizer_t *recognizer,
if(mrcp_resource_header_property_check(request,RECOGNIZER_HEADER_START_INPUT_TIMERS) == TRUE) {
recognizer->is_input_timer_on = request_recog_header->start_input_timers;
}
if(mrcp_resource_header_property_check(request,RECOGNIZER_HEADER_NO_INPUT_TIMEOUT) == TRUE) {
recognizer->properties.no_input_timeout = request_recog_header->no_input_timeout;
}
if(mrcp_resource_header_property_check(request,RECOGNIZER_HEADER_RECOGNITION_TIMEOUT) == TRUE) {
recognizer->properties.recognition_timeout = request_recog_header->recognition_timeout;
}
if(mrcp_resource_header_property_check(request,RECOGNIZER_HEADER_SAVE_WAVEFORM) == TRUE) {
recognizer->properties.save_waveform = request_recog_header->save_waveform;
}
}
/* check if waveform (utterance) should be saved */
if(recognizer->properties.save_waveform == TRUE) {
apr_status_t rv;
const char *waveform_file_name = apr_psprintf(channel->pool,"utter-%s-%d.pcm",
channel->id.buf,request->start_line.request_id);
char *waveform_file_path = NULL;
apr_filepath_merge(&waveform_file_path,recognizer->properties.save_waveform_dir,
waveform_file_name,0,channel->pool);
apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open Waveform File [%s] "APT_SIDRES_FMT,
waveform_file_path,RECOGNIZER_SIDRES(recognizer));
rv = apr_file_open(&recognizer->waveform,waveform_file_path,APR_CREATE|APR_TRUNCATE|APR_WRITE|APR_BINARY,
APR_OS_DEFAULT,channel->pool);
if(rv != APR_SUCCESS) {
apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot Open Waveform File to Write [%s] "APT_SIDRES_FMT,
waveform_file_path,RECOGNIZER_SIDRES(recognizer));
}
}
response->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS;
/* send asynchronous response */
mrcp_engine_channel_message_send(recognizer->channel,response);
mrcp_engine_channel_message_send(channel,response);
/* reset */
mpf_activity_detector_reset(recognizer->detector);
recognizer->noinput_timeout = 0;
recognizer->no_input_timeout = 0;
recognizer->recognition_timeout = 0;
recognizer->partial_result_timeout = 0;
recognizer->last_result = NULL;
@@ -560,7 +595,7 @@ static apt_bool_t pocketsphinx_recognize(pocketsphinx_recognizer_t *recognizer,
return TRUE;
}
/** Process GET-RESULTS request [RECOG] */
/** Process GET-RESULT request [RECOG] */
static apt_bool_t pocketsphinx_get_result(pocketsphinx_recognizer_t *recognizer, mrcp_message_t *request, mrcp_message_t *response)
{
if(pocketsphinx_result_build(recognizer,response) != TRUE) {
@@ -609,6 +644,11 @@ static apt_bool_t pocketsphinx_recognition_complete(pocketsphinx_recognizer_t *r
recognizer->inprogress_recog = NULL;
ps_end_utt(recognizer->decoder);
if(recognizer->waveform) {
apr_file_close(recognizer->waveform);
recognizer->waveform = NULL;
}
if(recognizer->stop_response) {
/* recognition has been stopped, send STOP response instead */
mrcp_message_t *response = recognizer->stop_response;
@@ -690,13 +730,10 @@ static apt_bool_t pocketsphinx_request_dispatch(pocketsphinx_recognizer_t *recog
static void* APR_THREAD_FUNC pocketsphinx_recognizer_run(apr_thread_t *thread, void *data)
{
pocketsphinx_recognizer_t *recognizer = data;
apt_bool_t status;
apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Run Recognition Thread "APT_SIDRES_FMT, RECOGNIZER_SIDRES(recognizer));
status = pocketsphinx_properties_load(recognizer);
/** Send response to channel_open request */
mrcp_engine_channel_open_respond(recognizer->channel,status);
mrcp_engine_channel_open_respond(recognizer->channel,TRUE);
do {
/** Wait for MRCP requests */
@@ -760,7 +797,7 @@ static apt_bool_t pocketsphinx_start_of_input(pocketsphinx_recognizer_t *recogni
/* set request state */
message->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS;
/* send asynch event */
/* send asynchronous event */
return mrcp_engine_channel_message_send(recognizer->channel,message);
}
@@ -811,6 +848,12 @@ static apt_bool_t pocketsphinx_stream_write(mpf_audio_stream_t *stream, const mp
return TRUE;
}
if(recognizer->waveform) {
/* write utterance to file */
apr_size_t size = frame->codec_frame.size;
apr_file_write(recognizer->waveform,frame->codec_frame.buffer,&size);
}
if(ps_process_raw(
recognizer->decoder,
(const int16 *)frame->codec_frame.buffer,
@@ -835,13 +878,18 @@ static apt_bool_t pocketsphinx_stream_write(mpf_audio_stream_t *stream, const mp
recognizer->last_result = apr_pstrdup(recognizer->channel->pool,hyp);
apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Get Recognition Partial Result [%s] Score [%d] "APT_SIDRES_FMT,
hyp,score,RECOGNIZER_SIDRES(recognizer));
/* reset input timer as we have partial match now */
if(score != 0 && recognizer->is_input_timer_on) {
recognizer->is_input_timer_on = FALSE;
}
}
}
}
if(recognizer->is_input_timer_on) {
recognizer->noinput_timeout += CODEC_FRAME_TIME_BASE;
if(recognizer->noinput_timeout == recognizer->properties.noinput_timeout) {
recognizer->no_input_timeout += CODEC_FRAME_TIME_BASE;
if(recognizer->no_input_timeout == recognizer->properties.no_input_timeout) {
apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Noinput Timeout Elapsed "APT_SIDRES_FMT,
RECOGNIZER_SIDRES(recognizer));
pocketsphinx_end_of_input(recognizer,RECOGNIZER_COMPLETION_CAUSE_NO_INPUT_TIMEOUT);

View File

@@ -0,0 +1,209 @@
/*
* Copyright 2008 Arsen Chaloyan
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <apr_xml.h>
#include "pocketsphinx_properties.h"
#include "apt_log.h"
static const apr_xml_elem* pocketsphinx_document_load(const char *file_path, apr_pool_t *pool)
{
apr_xml_parser *parser = NULL;
apr_xml_doc *doc = NULL;
const apr_xml_elem *root;
apr_file_t *fd = NULL;
apr_status_t rv;
apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Open PocketSphinx Config File [%s]",file_path);
rv = apr_file_open(&fd,file_path,APR_READ|APR_BINARY,0,pool);
if(rv != APR_SUCCESS) {
apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Open PocketSphinx Config File [%s]",file_path);
return FALSE;
}
rv = apr_xml_parse_file(pool,&parser,&doc,fd,2000);
if(rv != APR_SUCCESS) {
apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse PocketSphinx Config File [%s]",file_path);
apr_file_close(fd);
return FALSE;
}
root = doc->root;
if(!root || strcasecmp(root->name,"pocketsphinx") != 0) {
apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Document <%s>",root->name);
apr_file_close(fd);
return FALSE;
}
apr_file_close(fd);
return root;
}
static apt_bool_t sensitivity_properties_load(pocketsphinx_properties_t *properties, const apr_xml_elem *elem, apr_pool_t *pool)
{
const apr_xml_attr *attr;
for(attr = elem->attr; attr; attr = attr->next) {
if(strcasecmp(attr->name,"level") == 0) {
properties->sensitivity_level = atol(attr->value);
}
else if(strcasecmp(attr->name,"timeout") == 0) {
properties->sensitivity_timeout = atol(attr->value);
}
else {
apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name);
}
}
return TRUE;
}
static apt_bool_t timer_properties_load(pocketsphinx_properties_t *properties, const apr_xml_elem *elem, apr_pool_t *pool)
{
const apr_xml_attr *attr;
for(attr = elem->attr; attr; attr = attr->next) {
if(strcasecmp(attr->name,"noinput-timeout") == 0) {
properties->no_input_timeout = atol(attr->value);
}
else if(strcasecmp(attr->name,"recognition-timeout") == 0) {
properties->recognition_timeout = atol(attr->value);
}
else {
apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name);
}
}
return TRUE;
}
static apt_bool_t model_properties_load(pocketsphinx_properties_t *properties, const apr_xml_elem *elem, apr_pool_t *pool)
{
const apr_xml_attr *attr;
for(attr = elem->attr; attr; attr = attr->next) {
if(strcasecmp(attr->name,"dir") == 0) {
properties->data_dir = apr_pstrdup(pool,attr->value);
}
else if(strcasecmp(attr->name,"narrowband") == 0) {
properties->model_8k = apr_pstrdup(pool,attr->value);
}
else if(strcasecmp(attr->name,"wideband") == 0) {
properties->model_16k = apr_pstrdup(pool,attr->value);
}
else if(strcasecmp(attr->name,"dictionary") == 0) {
properties->dictionary = apr_pstrdup(pool,attr->value);
}
else if(strcasecmp(attr->name,"preferred") == 0) {
if(strcasecmp(attr->value,"narrowband") == 0) {
properties->preferred_model = POCKETSPHINX_MODEL_NARROWBAND;
}
else if(strcasecmp(attr->value,"wideband") == 0) {
properties->preferred_model = POCKETSPHINX_MODEL_WIDEBAND;
}
}
else {
apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name);
}
}
return TRUE;
}
static apt_bool_t save_waveform_properties_load(pocketsphinx_properties_t *properties, const apr_xml_elem *elem, apr_pool_t *pool)
{
const apr_xml_attr *attr;
for(attr = elem->attr; attr; attr = attr->next) {
if(strcasecmp(attr->name,"dir") == 0) {
properties->save_waveform_dir = apr_pstrdup(pool,attr->value);
}
else if(strcasecmp(attr->name,"enable") == 0) {
properties->save_waveform = atoi(attr->value);
}
else {
apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name);
}
}
return TRUE;
}
apt_bool_t pocketsphinx_properties_load(pocketsphinx_properties_t *properties,
const char *file_path,
const apt_dir_layout_t *dir_layout,
apr_pool_t *pool)
{
const apr_xml_elem *elem;
const apr_xml_elem *root;
char *path = NULL;
/* reset or set default properties */
properties->data_dir = NULL;
properties->dictionary = NULL;
properties->model_8k = NULL;
properties->model_16k = NULL;
properties->preferred_model = POCKETSPHINX_MODEL_NARROWBAND;
properties->no_input_timeout = 10000;
properties->recognition_timeout = 15000;
properties->partial_result_timeout = 100;
properties->save_waveform = TRUE;
properties->save_waveform_dir = NULL;
root = pocketsphinx_document_load(file_path,pool);
if(root) {
for(elem = root->first_child; elem; elem = elem->next) {
if(strcasecmp(elem->name,"sensitivity") == 0) {
sensitivity_properties_load(properties,elem,pool);
}
else if(strcasecmp(elem->name,"timers") == 0) {
timer_properties_load(properties,elem,pool);
}
else if(strcasecmp(elem->name,"model") == 0) {
model_properties_load(properties,elem,pool);
}
else if(strcasecmp(elem->name,"save-waveform") == 0) {
save_waveform_properties_load(properties,elem,pool);
}
else {
apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name);
}
}
}
/* verify loaded properties */
if(!properties->data_dir || *properties->data_dir == '\0') {
properties->data_dir = dir_layout->data_dir_path;
}
if(!properties->save_waveform_dir || *properties->save_waveform_dir == '\0') {
properties->save_waveform_dir = dir_layout->data_dir_path;
}
if(!properties->dictionary) {
properties->dictionary = "default.dic";
}
if(!properties->model_8k) {
properties->model_8k = "communicator";
}
if(!properties->model_16k) {
properties->model_16k = "wsj1";
}
if(apr_filepath_merge(&path,properties->data_dir,properties->dictionary,0,pool) == APR_SUCCESS) {
properties->dictionary = path;
}
if(apr_filepath_merge(&path,properties->data_dir,properties->model_8k,0,pool) == APR_SUCCESS) {
properties->model_8k = path;
}
if(apr_filepath_merge(&path,properties->data_dir,properties->model_16k,0,pool) == APR_SUCCESS) {
properties->model_16k = path;
}
return TRUE;
}