]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
commit dbea6143d6b63765f2d0eba26728c3903d3d2606
authorBrian West <brian@freeswitch.org>
Thu, 9 Jul 2009 15:19:27 +0000 (15:19 +0000)
committerBrian West <brian@freeswitch.org>
Thu, 9 Jul 2009 15:19:27 +0000 (15:19 +0000)
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Jul 8 17:37:24 2009 +0000

    Added yet another buffer of media frames mpf_frame_buffer.
    There are a number of similar buffers (mpf_jitter_buffer, mpf_buffer, mpf_frame_buffer). All of them produce mpf_frames as output, but input is somewhat dif
ferent. Input is RTP payload in case of mpf_jitter_buffer, synthesized chunks of voice in case of mpf_buffer, and mpf_frame in case of mpf_frame_buffer

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

commit 1bf7a66012180649bd1f01fd72e483a9e5de3495
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Jul 8 16:33:36 2009 +0000

    Fixed termination of client and server stacks (Issue-28)
    Network client/server stacks generated double TERMINATE_COMPLETE event, while mpf engine generated no TERMINATE_COMPLETE event.

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

commit 0327cf17779430b51290d22cc7d51130f997f2f2
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Jul 5 19:22:31 2009 +0000

    Enhanced flite plugin to
    - support more than one SPEAK requests in a session (SPEAK -> STOP -> SPEAK or SPEAK-> SPEAK-COMPLETE->SPEAK), task is created upon channel creation and is
waiting for consecutive SPEAK requests to process
    - properly handle race between STOP request and SPEAK-COMPLETE event
    - respond with IN-PROGRESS, when all the required parameters are checked to be valid and synthesizing is due to start

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

commit e2f73f9279e54ef3a40cb637a38ab1ff485ea5d3
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Jul 5 03:46:13 2009 +0000

    Separated flite voices (unified voice register/unregister routine, select voice by name)

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

commit 694783a527cb795ca45982c2388895da06dd6009
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Jul 4 05:06:17 2009 +0000

    Checked content-type to be "text/plain" as flite doesn't support SSML yet.

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

commit aafdc6e30e77c40e5470cce844f48ec28a254786
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Jul 3 14:55:10 2009 +0000

    Enhanced float value generation to use the precision (digits after decimal sign) user provides by removing optional trailing 0s (if any)
    Issue-35

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

commit bcc2f137956f5c532c0256b064c8a3d1015a46d0
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Jul 3 07:04:07 2009 +0000

    Enhanced RTP port management (Issue-34, Thanks cpsoares)

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

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@14166 d0543943-73ff-0310-b7d9-9358b9ac24b2

16 files changed:
libs/unimrcp/.update
libs/unimrcp/libs/apr-toolkit/include/apt_text_stream.h
libs/unimrcp/libs/apr-toolkit/src/apt_net_client_task.c
libs/unimrcp/libs/apr-toolkit/src/apt_net_server_task.c
libs/unimrcp/libs/apr-toolkit/src/apt_text_stream.c
libs/unimrcp/libs/mpf/Makefile.am
libs/unimrcp/libs/mpf/include/mpf_frame_buffer.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/mpf.vcproj
libs/unimrcp/libs/mpf/src/mpf_engine.c
libs/unimrcp/libs/mpf/src/mpf_frame_buffer.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_rtp_stream.c
libs/unimrcp/plugins/mrcp-flite/Makefile.am
libs/unimrcp/plugins/mrcp-flite/include/flite_voices.h [new file with mode: 0644]
libs/unimrcp/plugins/mrcp-flite/mrcpflite.vcproj
libs/unimrcp/plugins/mrcp-flite/src/flite_voices.c [new file with mode: 0644]
libs/unimrcp/plugins/mrcp-flite/src/mrcp_flite.c

index 61425074b3e827b062140209301b1a65c7c101b0..6f16710afd050e4395cc5f6a2105fbb007233f22 100644 (file)
@@ -1 +1 @@
-Wed Jul  1 19:53:07 CDT 2009
+Thu Jul  9 10:17:26 CDT 2009
index e5aca8ab67b8446b323d9dc82552cad61b4aa494..3a5a224aa34918f3969eba2d7d8f932b836960d1 100644 (file)
@@ -22,8 +22,6 @@
  * @brief Text Stream Parse/Generate Routine
  */ 
 
-#include <stdlib.h>
-#include <stdio.h>
 #include "apt_string.h"
 #include "apt_pair.h"
 
@@ -95,40 +93,17 @@ APT_DECLARE(apt_bool_t) apt_boolean_value_parse(const apt_str_t *str, apt_bool_t
 /** Generate boolean-value */
 APT_DECLARE(apt_bool_t) apt_boolean_value_generate(apt_bool_t value, apt_text_stream_t *str);
 
-
 /** Parse size_t value */
-static APR_INLINE apr_size_t apt_size_value_parse(const apt_str_t *str)
-{
-       return str->buf ? atol(str->buf) : 0;
-}
+APT_DECLARE(apr_size_t) apt_size_value_parse(const apt_str_t *str);
 
 /** Generate apr_size_t value */
-static APR_INLINE apt_bool_t apt_size_value_generate(apr_size_t value, apt_text_stream_t *stream)
-{
-       int length = sprintf(stream->pos, "%"APR_SIZE_T_FMT, value);
-       if(length <= 0) {
-               return FALSE;
-       }
-       stream->pos += length;
-       return TRUE;
-}
+APT_DECLARE(apt_bool_t) apt_size_value_generate(apr_size_t value, apt_text_stream_t *stream);
 
 /** Parse float value */
-static APR_INLINE float apt_float_value_parse(const apt_str_t *str)
-{
-       return str->buf ? (float)atof(str->buf) : 0;
-}
+APT_DECLARE(float) apt_float_value_parse(const apt_str_t *str);
 
 /** Generate float value */
-static APR_INLINE apt_bool_t apt_float_value_generate(float value, apt_text_stream_t *stream)
-{
-       int length = sprintf(stream->pos,"%.2f",value);
-       if(length <= 0) {
-               return FALSE;
-       }
-       stream->pos += length;
-       return TRUE;
-}
+APT_DECLARE(apt_bool_t) apt_float_value_generate(float value, apt_text_stream_t *stream);
 
 /** Generate string value */
 static APR_INLINE apt_bool_t apt_string_value_generate(const apt_str_t *str, apt_text_stream_t *stream)
index eb7cf6393de63c0bcd2280757dd19b3c8bcd399b..6e59440cbdc89df9ee1952ccb5f694c27294876e 100644 (file)
@@ -300,8 +300,6 @@ static apt_bool_t apt_net_client_task_run(apt_task_t *base)
        }
 
        apt_net_client_task_pollset_destroy(task);
-
-       apt_task_child_terminate(task->base);
        return TRUE;
 }
 
index 77c48b980aa5d218c0ced00756ca733420c5a149..4d994f4bedbec363befd8f271382ac0f4cb1c78d 100644 (file)
@@ -350,8 +350,6 @@ static apt_bool_t apt_net_server_task_run(apt_task_t *base)
        }
 
        apt_net_server_task_pollset_destroy(task);
-
-       apt_task_child_terminate(task->base);
        return TRUE;
 }
 
index 2735337959e5b34e2b62fd515d5526d2669b448f..a27606330168f3475ebcdda6180f35d1890337c4 100644 (file)
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <stdlib.h>
+#include <stdio.h>
 #include <apr_uuid.h>
 #include "apt_text_stream.h"
 
@@ -307,6 +309,45 @@ APT_DECLARE(apt_bool_t) apt_boolean_value_generate(apt_bool_t value, apt_text_st
        return TRUE;
 }
 
+/** Parse size_t value */
+APT_DECLARE(apr_size_t) apt_size_value_parse(const apt_str_t *str)
+{
+       return str->buf ? atol(str->buf) : 0;
+}
+
+/** Generate apr_size_t value */
+APT_DECLARE(apt_bool_t) apt_size_value_generate(apr_size_t value, apt_text_stream_t *stream)
+{
+       int length = sprintf(stream->pos, "%"APR_SIZE_T_FMT, value);
+       if(length <= 0) {
+               return FALSE;
+       }
+       stream->pos += length;
+       return TRUE;
+}
+
+/** Parse float value */
+APT_DECLARE(float) apt_float_value_parse(const apt_str_t *str)
+{
+       return str->buf ? (float)atof(str->buf) : 0;
+}
+
+/** Generate float value */
+APT_DECLARE(apt_bool_t) apt_float_value_generate(float value, apt_text_stream_t *stream)
+{
+       char *end;
+       int length = sprintf(stream->pos,"%f",value);
+       if(length <= 0) {
+               return FALSE;
+       }
+
+       /* remove trailing 0s (if any) */
+       end = stream->pos + length -1;
+       while(*end == 0x30 && end != stream->pos) end--;
+
+       stream->pos = end + 1;
+       return TRUE;
+}
 
 /** Generate value plus the length (number of digits) of the value itself. */
 APT_DECLARE(apt_bool_t) apt_var_length_value_generate(apr_size_t *value, apr_size_t max_count, apt_str_t *str)
index 65f14934991f68c9000026275f5e7850ca6edbe3..4a73d9132535abaff53d4f62aadfeecd43565548 100644 (file)
@@ -20,6 +20,7 @@ include_HEADERS          = codecs/g711/g711.h \
                            include/mpf_context.h \
                            include/mpf_engine.h \
                            include/mpf_frame.h \
+                           include/mpf_frame_buffer.h \
                            include/mpf_message.h \
                            include/mpf_object.h \
                            include/mpf_stream.h \
@@ -55,6 +56,7 @@ libmpf_la_SOURCES        = codecs/g711/g711.c \
                            src/mpf_termination.c \
                            src/mpf_rtp_termination_factory.c \
                            src/mpf_file_termination_factory.c \
+                           src/mpf_frame_buffer.c \
                            src/mpf_timer.c \
                            src/mpf_encoder.c \
                            src/mpf_decoder.c \
diff --git a/libs/unimrcp/libs/mpf/include/mpf_frame_buffer.h b/libs/unimrcp/libs/mpf/include/mpf_frame_buffer.h
new file mode 100644 (file)
index 0000000..8573963
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#ifndef __MPF_FRAME_BUFFER_H__
+#define __MPF_FRAME_BUFFER_H__
+
+/**
+ * @file mpf_frame_buffer.h
+ * @brief Buffer of Media Frames
+ */ 
+
+#include "mpf_frame.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque frame buffer declaration */
+typedef struct mpf_frame_buffer_t mpf_frame_buffer_t;
+
+
+/** Create frame buffer */
+mpf_frame_buffer_t* mpf_frame_buffer_create(apr_size_t frame_size, apr_size_t frame_count, apr_pool_t *pool);
+
+/** Destroy frame buffer */
+void mpf_frame_buffer_destroy(mpf_frame_buffer_t *buffer);
+
+/** Restart frame buffer */
+apt_bool_t mpf_frame_buffer_restart(mpf_frame_buffer_t *buffer);
+
+/** Write frame to buffer */
+apt_bool_t mpf_frame_buffer_write(mpf_frame_buffer_t *buffer, const mpf_frame_t *frame);
+
+/** Read frame from buffer */
+apt_bool_t mpf_frame_buffer_read(mpf_frame_buffer_t *buffer, mpf_frame_t *frame);
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_FRAME_BUFFER_H__*/
index d58fee87e7616060f4aed11590c9a3014449d9ca..6efaf489b86df8eaf15b21a3e3688c6921339db5 100644 (file)
                                RelativePath=".\include\mpf_frame.h"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_frame_buffer.h"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath=".\include\mpf_jitter_buffer.h"\r
                                >\r
                                RelativePath=".\src\mpf_file_termination_factory.c"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_frame_buffer.c"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath=".\src\mpf_jitter_buffer.c"\r
                                >\r
index 42aee780fc1cdeda876eceea899c65ddf4551f80..2d34b67cfea2bdb3796779ea0858e717e247789c 100644 (file)
@@ -128,6 +128,7 @@ static apt_bool_t mpf_engine_terminate(apt_task_t *task)
 
        mpf_timer_stop(engine->timer);
        mpf_engine_contexts_destroy(engine);
+       apt_task_child_terminate(task);
        return TRUE;
 }
 
diff --git a/libs/unimrcp/libs/mpf/src/mpf_frame_buffer.c b/libs/unimrcp/libs/mpf/src/mpf_frame_buffer.c
new file mode 100644 (file)
index 0000000..bec7e5a
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2009 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 "mpf_frame_buffer.h"
+
+struct mpf_frame_buffer_t {
+       apr_byte_t         *raw_data;
+       mpf_frame_t        *frames;
+       apr_size_t          frame_count;
+       apr_size_t          frame_size;
+
+       apr_size_t          write_pos;
+       apr_size_t          read_pos;
+
+       apr_thread_mutex_t *guard;
+       apr_pool_t         *pool;
+};
+
+
+mpf_frame_buffer_t* mpf_frame_buffer_create(apr_size_t frame_size, apr_size_t frame_count, apr_pool_t *pool)
+{
+       apr_size_t i;
+       mpf_frame_buffer_t *buffer = apr_palloc(pool,sizeof(mpf_frame_buffer_t));
+
+       buffer->frame_size = frame_size;
+       buffer->frame_count = frame_count;
+       buffer->raw_data = apr_palloc(pool,buffer->frame_size*buffer->frame_count);
+       buffer->frames = apr_palloc(pool,sizeof(mpf_frame_t)*buffer->frame_count);
+       for(i=0; i<buffer->frame_count; i++) {
+               buffer->frames[i].type = MEDIA_FRAME_TYPE_NONE;
+               buffer->frames[i].codec_frame.buffer = buffer->raw_data + i*buffer->frame_size;
+       }
+
+       buffer->write_pos = buffer->read_pos = 0;
+       apr_thread_mutex_create(&buffer->guard,APR_THREAD_MUTEX_UNNESTED,pool);
+       return buffer;
+}
+
+void mpf_frame_buffer_destroy(mpf_frame_buffer_t *buffer)
+{
+       if(buffer->guard) {
+               apr_thread_mutex_destroy(buffer->guard);
+               buffer->guard = NULL;
+       }
+}
+
+apt_bool_t mpf_frame_buffer_restart(mpf_frame_buffer_t *buffer)
+{
+       buffer->write_pos = buffer->read_pos;
+       return TRUE;
+}
+
+static APR_INLINE mpf_frame_t* mpf_frame_buffer_frame_get(mpf_frame_buffer_t *buffer, apr_size_t pos)
+{
+       apr_size_t index = pos % buffer->frame_count;
+       return &buffer->frames[index];
+}
+
+apt_bool_t mpf_frame_buffer_write(mpf_frame_buffer_t *buffer, const mpf_frame_t *frame)
+{
+       mpf_frame_t *write_frame;
+       void *data = frame->codec_frame.buffer;
+       apr_size_t size = frame->codec_frame.size;
+
+       apr_thread_mutex_lock(buffer->guard);
+       while(buffer->write_pos - buffer->read_pos < buffer->frame_count && size >= buffer->frame_size) {
+               write_frame = mpf_frame_buffer_frame_get(buffer,buffer->write_pos);
+               write_frame->type = frame->type;
+               write_frame->codec_frame.size = buffer->frame_size;
+               memcpy(
+                       write_frame->codec_frame.buffer,
+                       data,
+                       write_frame->codec_frame.size);
+
+               data = (char*)data + buffer->frame_size;
+               size -= buffer->frame_size;
+               buffer->write_pos ++;
+       }
+
+       apr_thread_mutex_unlock(buffer->guard);
+       /* if size != 0 => non frame alligned or buffer is full */
+       return size == 0 ? TRUE : FALSE;
+}
+
+apt_bool_t mpf_frame_buffer_read(mpf_frame_buffer_t *buffer, mpf_frame_t *media_frame)
+{
+       apr_thread_mutex_lock(buffer->guard);
+       if(buffer->write_pos > buffer->read_pos) {
+               /* normal read */
+               mpf_frame_t *src_media_frame = mpf_frame_buffer_frame_get(buffer,buffer->read_pos);
+               media_frame->type = src_media_frame->type;
+               if(media_frame->type & MEDIA_FRAME_TYPE_AUDIO) {
+                       media_frame->codec_frame.size = src_media_frame->codec_frame.size;
+                       memcpy(
+                               media_frame->codec_frame.buffer,
+                               src_media_frame->codec_frame.buffer,
+                               media_frame->codec_frame.size);
+               }
+               if(media_frame->type & MEDIA_FRAME_TYPE_EVENT) {
+                       media_frame->event_frame = src_media_frame->event_frame;
+               }
+               src_media_frame->type = MEDIA_FRAME_TYPE_NONE;
+               buffer->read_pos ++;
+       }
+       else {
+               /* underflow */
+               media_frame->type = MEDIA_FRAME_TYPE_NONE;
+       }
+       apr_thread_mutex_unlock(buffer->guard);
+       return TRUE;
+}
index 3956d1e6e3de842aa08d7224b749dc60113425b9..d97b1a81cbbbfecd515728250597a6bd6f094a84 100644 (file)
@@ -83,21 +83,6 @@ MPF_DECLARE(mpf_audio_stream_t*) mpf_rtp_stream_create(mpf_termination_t *termin
        return rtp_stream->base;
 }
 
-static void mpf_rtp_stream_ip_port_set(mpf_rtp_media_descriptor_t *media, mpf_rtp_config_t *config)
-{
-       if(media->base.ip.length == 0) {
-               media->base.ip = config->ip;
-               media->base.ext_ip = config->ext_ip;
-       }
-       if(media->base.port == 0) {
-               media->base.port = config->rtp_port_cur;
-               config->rtp_port_cur += 2;
-               if(config->rtp_port_cur == config->rtp_port_max) {
-                       config->rtp_port_cur = config->rtp_port_min;
-               }
-       }
-}
-
 static apt_bool_t mpf_rtp_stream_local_media_create(mpf_rtp_stream_t *rtp_stream, mpf_rtp_media_descriptor_t *local_media, mpf_rtp_media_descriptor_t *remote_media)
 {
        apt_bool_t status = TRUE;
@@ -111,9 +96,31 @@ static apt_bool_t mpf_rtp_stream_local_media_create(mpf_rtp_stream_t *rtp_stream
        if(remote_media) {
                local_media->base.id = remote_media->base.id;
        }
+       if(local_media->base.ip.length == 0) {
+               local_media->base.ip = rtp_stream->config->ip;
+               local_media->base.ext_ip = rtp_stream->config->ext_ip;
+       }
+       if(local_media->base.port == 0) {
+               /* RTP port management */
+               apr_port_t first_port_in_search = rtp_stream->config->rtp_port_cur;
+               apt_bool_t is_port_ok = FALSE;
 
-       mpf_rtp_stream_ip_port_set(local_media,rtp_stream->config);
-       if(mpf_rtp_socket_create(rtp_stream,local_media) == FALSE) {
+               do {
+                       local_media->base.port = rtp_stream->config->rtp_port_cur;
+                       rtp_stream->config->rtp_port_cur += 2;
+                       if(rtp_stream->config->rtp_port_cur == rtp_stream->config->rtp_port_max) {
+                               rtp_stream->config->rtp_port_cur = rtp_stream->config->rtp_port_min;
+                       }
+                       if(mpf_rtp_socket_create(rtp_stream,local_media) == TRUE) {
+                               is_port_ok = TRUE;
+                       }
+               } while((is_port_ok == FALSE) && (first_port_in_search != rtp_stream->config->rtp_port_cur));
+               if(is_port_ok == FALSE) {
+                       local_media->base.state = MPF_MEDIA_DISABLED;
+                       status = FALSE;
+               }
+       }
+       else if(mpf_rtp_socket_create(rtp_stream,local_media) == FALSE) {
                local_media->base.state = MPF_MEDIA_DISABLED;
                status = FALSE;
        }
index b48f753614d0cec8eec4ed1cd2d1bfea9828cc64..0e1dcbd58f5c4cb8a245fe73bb156f56e88dff7b 100644 (file)
@@ -14,6 +14,6 @@ INCLUDES                   = -Iinclude \
 
 plugin_LTLIBRARIES         = mrcpflite.la
 
-mrcpflite_la_SOURCES       = src/mrcp_flite.c
+mrcpflite_la_SOURCES       = src/mrcp_flite.c src/flite_voices.c
 mrcpflite_la_LDFLAGS       = -module $(PLUGIN_LT_VERSION)
 mrcpflite_la_LIBADD        = $(UNIMRCP_FLITE_LIBS) -lm
diff --git a/libs/unimrcp/plugins/mrcp-flite/include/flite_voices.h b/libs/unimrcp/plugins/mrcp-flite/include/flite_voices.h
new file mode 100644 (file)
index 0000000..ab896f1
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#ifndef __FLITE_VOICES_H__
+#define __FLITE_VOICES_H__
+
+/**
+ * @file flite_voices.h
+ * @brief Flite Voices
+ */ 
+
+#include <flite.h>
+#include <apr_hash.h>
+#include "mrcp_message.h"
+
+APT_BEGIN_EXTERN_C
+
+
+typedef struct flite_voices_t flite_voices_t;
+
+flite_voices_t* flite_voices_load(apr_pool_t *pool);
+void flite_voices_unload(flite_voices_t *voices);
+
+cst_voice* flite_voices_best_match_get(flite_voices_t *voices, mrcp_message_t *message);
+
+APT_END_EXTERN_C
+
+#endif /*__FLITE_VOICES_H__*/
index b271fd2e283f4516b30a2eb3f54d0119eb5643aa..46867d78166cfe5e3f94d84ddbe7ebdbddcb1a3b 100644 (file)
                        Filter="h;hpp;hxx;hm;inl;inc;xsd"
                        UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
                        >
+                       <File
+                               RelativePath=".\include\flite_voices.h"
+                               >
+                       </File>
                </Filter>
                <Filter
                        Name="src"
                        Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
                        >
+                       <File
+                               RelativePath=".\src\flite_voices.c"
+                               >
+                       </File>
                        <File
                                RelativePath=".\src\mrcp_flite.c"
                                >
diff --git a/libs/unimrcp/plugins/mrcp-flite/src/flite_voices.c b/libs/unimrcp/plugins/mrcp-flite/src/flite_voices.c
new file mode 100644 (file)
index 0000000..eb37963
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * 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 "flite_voices.h"
+#include "mrcp_synth_header.h"
+
+typedef struct flite_voice_t flite_voice_t;
+
+/** Declaration of flite voice */
+struct flite_voice_t {
+       const char *name;
+       cst_voice  *self;
+       cst_voice* (*register_voice)(void);
+       void (*unregister_voice)(cst_voice *);
+};
+
+struct flite_voices_t {
+       apr_hash_t *table;
+       apr_pool_t *pool;
+};
+
+
+/* declarations for flite voices */
+cst_voice *register_cmu_us_awb(void);
+cst_voice *register_cmu_us_kal(void);
+cst_voice *register_cmu_us_rms(void);
+cst_voice *register_cmu_us_slt(void);
+void unregister_cmu_us_awb(cst_voice * v);
+void unregister_cmu_us_kal(cst_voice * v);
+void unregister_cmu_us_rms(cst_voice * v);
+void unregister_cmu_us_slt(cst_voice * v);
+
+
+static apt_bool_t flite_voices_init(flite_voices_t *voices, apr_pool_t *pool)
+{
+       flite_voice_t *voice;
+
+       voice = apr_palloc(pool,sizeof(flite_voice_t));
+       voice->name = "awb";
+       voice->self = NULL;
+       voice->register_voice = register_cmu_us_awb;
+       voice->unregister_voice = unregister_cmu_us_awb;
+       apr_hash_set(voices->table,voice->name,APR_HASH_KEY_STRING,voice);
+
+       voice = apr_palloc(pool,sizeof(flite_voice_t));
+       voice->name = "kal";
+       voice->self = NULL;
+       voice->register_voice = register_cmu_us_kal;
+       voice->unregister_voice = unregister_cmu_us_kal;
+       apr_hash_set(voices->table,voice->name,APR_HASH_KEY_STRING,voice);
+
+       voice = apr_palloc(pool,sizeof(flite_voice_t));
+       voice->name = "rms";
+       voice->self = NULL;
+       voice->register_voice = register_cmu_us_rms;
+       voice->unregister_voice = unregister_cmu_us_rms;
+       apr_hash_set(voices->table,voice->name,APR_HASH_KEY_STRING,voice);
+
+       voice = apr_palloc(pool,sizeof(flite_voice_t));
+       voice->name = "slt";
+       voice->self = NULL;
+       voice->register_voice = register_cmu_us_slt;
+       voice->unregister_voice = unregister_cmu_us_slt;
+       apr_hash_set(voices->table,voice->name,APR_HASH_KEY_STRING,voice);
+
+       return TRUE;
+}
+
+
+flite_voices_t* flite_voices_load(apr_pool_t *pool)
+{
+       flite_voice_t *voice;
+       apr_hash_index_t *it;
+       void *val;
+
+       flite_voices_t *voices = apr_palloc(pool,sizeof(flite_voices_t));
+       voices->pool = pool;
+       voices->table = apr_hash_make(pool);
+
+       /* init voices */
+       flite_voices_init(voices,pool);
+
+       /* register voices */
+       it = apr_hash_first(pool,voices->table);
+       /* walk through the voices and register them */
+       for(; it; it = apr_hash_next(it)) {
+               apr_hash_this(it,NULL,NULL,&val);
+               voice = val;
+               if(voice) {
+                       voice->self = voice->register_voice();
+               }
+       }
+
+       return voices;
+}
+
+void flite_voices_unload(flite_voices_t *voices)
+{
+       flite_voice_t *voice;
+       apr_hash_index_t *it;
+       void *val;
+
+       /* unregister voices */
+       it = apr_hash_first(voices->pool,voices->table);
+       /* walk through the voices and register them */
+       for(; it; it = apr_hash_next(it)) {
+               apr_hash_this(it,NULL,NULL,&val);
+               voice = val;
+               if(voice && voice->self) {
+                       voice->unregister_voice(voice->self);
+               }
+       }
+}
+
+cst_voice* flite_voices_best_match_get(flite_voices_t *voices, mrcp_message_t *message)
+{
+       cst_voice *voice = NULL;
+       const char *voice_name = NULL;
+       mrcp_synth_header_t *synth_header = mrcp_resource_header_get(message);
+       if(synth_header) {
+               if(mrcp_resource_header_property_check(message,SYNTHESIZER_HEADER_VOICE_NAME) == TRUE) {
+                       voice_name = synth_header->voice_param.name.buf;
+               }
+       }
+
+       if(voice_name) {
+               /* get voice by name */
+               flite_voice_t *flite_voice;
+               flite_voice = apr_hash_get(voices->table,voice_name,APR_HASH_KEY_STRING);
+               if(flite_voice) {
+                       voice = flite_voice->self;
+               }
+       }
+
+       if(!voice) {
+               /* still no voice found, get the default one */
+               flite_voice_t *flite_voice = NULL;
+               void *val;
+               apr_hash_index_t *it = apr_hash_first(voices->pool,voices->table);
+               apr_hash_this(it,NULL,NULL,&val);
+               if(val) {
+                       flite_voice = val;
+                       voice = flite_voice->self;
+               }
+       }
+       return voice;
+}
index 1db710ed0c0bc0aea6d57a62a05cf6442ea39ec3..a8b8a803aaf96cb3c027139243e30b01b88a1262 100644 (file)
@@ -24,6 +24,7 @@
  * 4. Methods (callbacks) of the MPF engine stream MUST not block.
  */
 
+#include "flite_voices.h"
 #include "mrcp_resource_engine.h"
 #include "mrcp_synth_resource.h"
 #include "mrcp_synth_header.h"
@@ -33,7 +34,6 @@
 #include "apr_time.h"
 #include "apt_consumer_task.h"
 #include "apt_log.h"
-#include "flite.h"
 
 typedef struct flite_synth_engine_t flite_synth_engine_t;
 typedef struct flite_synth_channel_t flite_synth_channel_t;
@@ -57,8 +57,6 @@ static apt_bool_t flite_synth_channel_open(mrcp_engine_channel_t *channel);
 static apt_bool_t flite_synth_channel_close(mrcp_engine_channel_t *channel);
 static apt_bool_t flite_synth_channel_request_process(mrcp_engine_channel_t *channel, mrcp_message_t *request);
 
-static apt_bool_t flite_synth_channel_close_t(mrcp_engine_channel_t *channel); // wait for speak thread
-
 /** flite channel methods for processing MRCP channel request **/
 static apt_bool_t flite_synth_channel_speak(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response);
 static apt_bool_t flite_synth_channel_stop(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response);
@@ -75,15 +73,12 @@ static const struct mrcp_engine_channel_method_vtable_t channel_vtable = {
 };
 
 /** Declaration of synthesizer audio stream methods */
-static apt_bool_t flite_synth_stream_destroy(mpf_audio_stream_t *stream);
-static apt_bool_t flite_synth_stream_open(mpf_audio_stream_t *stream);
-static apt_bool_t flite_synth_stream_close(mpf_audio_stream_t *stream);
 static apt_bool_t flite_synth_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame);
 
 static const mpf_audio_stream_vtable_t audio_stream_vtable = {
-       flite_synth_stream_destroy,
-       flite_synth_stream_open,
-       flite_synth_stream_close,
+       NULL,
+       NULL,
+       NULL,
        flite_synth_stream_read,
        NULL,
        NULL,
@@ -92,39 +87,25 @@ static const mpf_audio_stream_vtable_t audio_stream_vtable = {
 
 /** Declaration of flite synthesizer engine */
 struct flite_synth_engine_t {
-       int                                      iChannels;
-       struct {
-               cst_voice *awb;
-               cst_voice *kal;
-               cst_voice *rms;
-               cst_voice *slt;
-       } voices;
+       /** Table of flite voices */
+       flite_voices_t *voices;
+       int             iChannels;
 };
 
-/** declarations for flite voices **/
-cst_voice *register_cmu_us_awb(void);
-cst_voice *register_cmu_us_kal(void);
-cst_voice *register_cmu_us_rms(void);
-cst_voice *register_cmu_us_slt(void);
-void unregister_cmu_us_awb(cst_voice * v);
-void unregister_cmu_us_kal(cst_voice * v);
-void unregister_cmu_us_rms(cst_voice * v);
-void unregister_cmu_us_slt(cst_voice * v);
-
-
 /** Declaration of flite synthesizer channel */
 struct flite_synth_channel_t {
-       flite_synth_engine_t    *flite_engine;  // Back pointer to engine 
-       mrcp_engine_channel_t   *channel;               // Engine channel base 
-       mrcp_message_t                  *speak_request; // Active (in-progress) speak request
-       mrcp_message_t                  *stop_response; // Pending stop response
-       apt_bool_t                               paused;                // Is paused
-       mpf_buffer_t                    *audio_buffer;  // Audio buffer
-       int                                              iId;                   // Synth channel simultaneous reference count
-       cst_voice                               *voice;
-       apr_pool_t                              *pool;
-       apt_consumer_task_t     *task;
-       apr_thread_mutex_t          *channel_guard;
+       flite_synth_engine_t  *flite_engine;  /* Back pointer to engine */
+       mrcp_engine_channel_t *channel;           /* Engine channel base */
+       mrcp_message_t            *speak_request; /* Active (in-progress) speak request */
+       mrcp_message_t            *speak_response;/* Pending speak response */
+       mrcp_message_t        *stop_response; /* Pending stop response */
+       apt_bool_t             synthesizing;  /* Is synthesizer task processing speak request */
+       apt_bool_t             paused;        /* Is paused */
+       mpf_buffer_t          *audio_buffer;  /* Audio buffer */
+       int                    iId;           /* Synth channel simultaneous reference count */
+       apr_pool_t            *pool;
+       apt_task_t            *task;
+       apt_task_msg_pool_t   *msg_pool;
 };
 
 /** Declaration of flite synthesizer task message */
@@ -135,8 +116,8 @@ struct flite_speak_msg_t {
 
 typedef struct flite_speak_msg_t flite_speak_msg_t;
 
-// we have a special task for the actual synthesis - 
-// the task is created when a mrcp speak message is received
+/* we have a special task for the actual synthesis - 
+   the task is created when a mrcp speak message is received */
 static apt_bool_t flite_speak(apt_task_t *task, apt_task_msg_t *msg);
 
 /** Declare this macro to use log routine of the server where the plugin is loaded from */
@@ -147,7 +128,6 @@ MRCP_PLUGIN_DECLARE(mrcp_resource_engine_t*) mrcp_plugin_create(apr_pool_t *pool
 {
        /* create flite engine */
        flite_synth_engine_t *flite_engine = (flite_synth_engine_t *) apr_palloc(pool,sizeof(flite_synth_engine_t));
-
        flite_engine->iChannels = 0;
 
        /* create resource engine base */
@@ -172,13 +152,10 @@ static apt_bool_t flite_synth_engine_open(mrcp_resource_engine_t *engine)
        apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_engine_open");
 
        flite_init();
-       flite_engine->voices.awb = register_cmu_us_awb();
-       flite_engine->voices.kal = register_cmu_us_kal();
-       flite_engine->voices.rms = register_cmu_us_rms();
-       flite_engine->voices.slt = register_cmu_us_slt();
 
-       apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite init success");
+       flite_engine->voices = flite_voices_load(engine->pool);
 
+       apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite init success");
        return TRUE;
 }
 
@@ -188,14 +165,36 @@ static apt_bool_t flite_synth_engine_close(mrcp_resource_engine_t *engine)
        flite_synth_engine_t *flite_engine = (flite_synth_engine_t *) engine->obj;
        apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_engine_close");
 
-       unregister_cmu_us_awb(flite_engine->voices.awb);
-       unregister_cmu_us_kal(flite_engine->voices.kal);
-       unregister_cmu_us_rms(flite_engine->voices.rms);
-       unregister_cmu_us_slt(flite_engine->voices.slt);
+       flite_voices_unload(flite_engine->voices);
 
        return TRUE;
 }
 
+static apt_bool_t flite_synth_task_create(flite_synth_channel_t *synth_channel)
+{
+       apt_task_msg_pool_t *msg_pool = apt_task_msg_pool_create_dynamic( sizeof(flite_speak_msg_t),synth_channel->pool);
+       apt_task_vtable_t *task_vtable = 0;
+       apt_consumer_task_t *consumer_task = 0;
+
+       /* create task/thread to run flite synthesizer in */
+    consumer_task = apt_consumer_task_create(synth_channel, msg_pool, synth_channel->pool);
+       if(!consumer_task) {
+               apt_log(APT_LOG_MARK,APT_PRIO_ERROR, "flite_synth_channel_speak failed to create flite speak task - channel:%d", synth_channel->iId);
+               return FALSE;
+       }
+
+       task_vtable = apt_consumer_task_vtable_get(consumer_task);
+       if(!task_vtable) {
+               apt_log(APT_LOG_MARK,APT_PRIO_ERROR, "flite_synth_channel_speak cannot use flite speak task vtable - channel:%d", synth_channel->iId);
+               return FALSE;
+       }
+
+       task_vtable->process_msg = flite_speak;
+       synth_channel->msg_pool = msg_pool;
+       synth_channel->task = apt_consumer_task_base_get(consumer_task);
+       return TRUE;
+}
+
 /** Create flite synthesizer channel derived from engine channel base */
 static mrcp_engine_channel_t* flite_synth_engine_channel_create(mrcp_resource_engine_t *engine, apr_pool_t *pool)
 {
@@ -204,30 +203,31 @@ static mrcp_engine_channel_t* flite_synth_engine_channel_create(mrcp_resource_en
        mpf_codec_descriptor_t *codec_descriptor = NULL;
 
        apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_engine_channel_create");
-
-//     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 = 16000;
+#if 0
+       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 = 16000;
+#endif
 
        synth_channel->flite_engine = (flite_synth_engine_t *) engine->obj;
        synth_channel->speak_request = NULL; // no active speak request in progress
+       synth_channel->speak_response = NULL;
        synth_channel->stop_response = NULL;
+       synth_channel->synthesizing = FALSE;
        synth_channel->paused = FALSE;
        synth_channel->pool = pool;
        synth_channel->audio_buffer = NULL;
-       synth_channel->voice = NULL;
        synth_channel->iId = 0;
-
-       if (apr_thread_mutex_create(&synth_channel->channel_guard,APR_THREAD_MUTEX_DEFAULT,pool) != APR_SUCCESS) 
-       {
-               apt_log(APT_LOG_MARK, APT_PRIO_ERROR, "Failed to create channel guard");
+       synth_channel->task = NULL;
+       synth_channel->msg_pool = NULL;
+       if(flite_synth_task_create(synth_channel) != TRUE) {
+               apt_log(APT_LOG_MARK, APT_PRIO_WARNING, "flite_synth_task_create failed");
                return NULL;
        }
 
-
        /* create engine channel base */
        synth_channel->channel = mrcp_engine_source_channel_create(
                        engine,               /* resource engine */
@@ -237,9 +237,9 @@ static mrcp_engine_channel_t* flite_synth_engine_channel_create(mrcp_resource_en
                        codec_descriptor,     /* codec descriptor might be NULL by default */
                        pool);                /* pool to allocate memory from */
        
-       if (!synth_channel->channel) 
-       {
+       if(!synth_channel->channel) {
                apt_log(APT_LOG_MARK, APT_PRIO_WARNING, "flite_synth_engine_channel_create failed");
+               apt_task_destroy(synth_channel->task);
                return NULL;            
        }
 
@@ -247,7 +247,6 @@ static mrcp_engine_channel_t* flite_synth_engine_channel_create(mrcp_resource_en
        synth_channel->iId = ++synth_channel->flite_engine->iChannels;
 
        apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_engine_channel_create created channel %d", synth_channel->iId);
-
        return synth_channel->channel;
 }
 
@@ -256,24 +255,12 @@ static apt_bool_t flite_synth_channel_destroy(mrcp_engine_channel_t *channel)
 {
        flite_synth_channel_t *synth_channel = (flite_synth_channel_t *) channel->method_obj;
        apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_channel_destroy - channel %d", synth_channel->iId);
-       if(synth_channel->task)
-       {
-               apt_task_t *task = apt_consumer_task_base_get(synth_channel->task);
-               if (!task || !apt_task_destroy(task))
-               {
-                       apt_log(APT_LOG_MARK, APT_PRIO_WARNING, "Speak task destroy failed - channel %d", synth_channel->iId);
-               }
-               else
-               {
-                       apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "Speak task destroyed - channel %d", synth_channel->iId);
-               }
+       if(synth_channel->task) {
+               apt_task_destroy(synth_channel->task);
+               synth_channel->task = NULL;
        }
        
-       synth_channel->task = NULL;
        synth_channel->flite_engine->iChannels--;
-
-       apr_thread_mutex_destroy(synth_channel->channel_guard);
-
        return TRUE;
 }
 
@@ -283,7 +270,15 @@ static apt_bool_t flite_synth_channel_open(mrcp_engine_channel_t *channel)
        flite_synth_channel_t *synth_channel = (flite_synth_channel_t *) channel->method_obj;
        apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_channel_open - channel %d", synth_channel->iId);
 
-       synth_channel->voice = synth_channel->flite_engine->voices.awb;
+       if(synth_channel->task) {
+               if(apt_task_start(synth_channel->task) == TRUE) {
+                       apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "Speak task started - channel %d", synth_channel->iId);
+               }
+               else {
+                       apt_log(APT_LOG_MARK, APT_PRIO_WARNING, "Speak task start failed - channel %d", synth_channel->iId);
+               }
+       }
+
        return mrcp_engine_channel_open_respond(channel,TRUE);
 }
 
@@ -292,8 +287,16 @@ static apt_bool_t flite_synth_channel_close(mrcp_engine_channel_t *channel)
 {
        flite_synth_channel_t *synth_channel = (flite_synth_channel_t *) channel->method_obj;
        apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_channel_close - channel %d", synth_channel->iId);
-       // create thread to wait for speak thread to terminate
-       flite_synth_channel_close_t(channel);
+
+       if(synth_channel->task) {
+               if(apt_task_terminate(synth_channel->task,TRUE) == TRUE) {
+                       apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "Speak task terminated - channel %d", synth_channel->iId);
+               }
+               else {
+                       apt_log(APT_LOG_MARK, APT_PRIO_WARNING, "Speak task terminate failed - channel %d", synth_channel->iId);
+               }
+       }
+       mrcp_engine_channel_close_respond(channel);
        return TRUE; 
 }
 
@@ -308,18 +311,6 @@ static apt_bool_t flite_synth_channel_request_process(mrcp_engine_channel_t *cha
 
        switch(request->start_line.method_id) {
                case SYNTHESIZER_SET_PARAMS:
-                               // TODO set voices
-                               //      if (!strcasecmp(voice_name, "awb")) {
-                               //              synth_channel->voice = voices.awb;
-                               //      } else if (!strcasecmp(voice_name, "kal")) {
-                               //              synth_channel->voice = voices.kal;
-                               //      } else if (!strcasecmp(voice_name, "rms")) {
-                               //              synth_channel->voice = voices.rms;
-                               //      } else if (!strcasecmp(voice_name, "slt")) {
-                               //              synth_channel->voice = voices.slt;
-                               //      } else {
-                               //              apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "Valid voice names are awb, kal, rms or slt");
-                               //      }
                        break;
                case SYNTHESIZER_GET_PARAMS:
                        break;
@@ -350,92 +341,67 @@ static apt_bool_t flite_synth_channel_request_process(mrcp_engine_channel_t *cha
                mrcp_engine_channel_message_send(channel,response);
        }
        return TRUE;
-
 }
 
-static apt_bool_t flite_synth_channel_close_t(mrcp_engine_channel_t *channel)
+/** Process SPEAK request */
+static apt_bool_t synth_response_construct(mrcp_message_t *response, mrcp_status_code_e status_code, mrcp_synth_completion_cause_e completion_cause)
 {
-       flite_synth_channel_t *synth_channel = (flite_synth_channel_t *) channel->method_obj;
-       apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_channel_close_t - channel %d", synth_channel->iId);
-       
-       if (synth_channel->task) 
-       {
-               apt_task_t *task = apt_consumer_task_base_get(synth_channel->task);
-               if (!apt_task_terminate(task,TRUE))
-               {
-                       apt_log(APT_LOG_MARK, APT_PRIO_WARNING, "Speak task terminate failed - channel %d", synth_channel->iId);
-               }
-               else
-               {
-                       apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "Speak task terminated - channel %d", synth_channel->iId);
-                       apt_task_destroy(task);
-                       synth_channel->task = 0;
-               }
+       mrcp_synth_header_t *synth_header = mrcp_resource_header_prepare(response);
+       if(!synth_header) {
+               return FALSE;
        }
-       mrcp_engine_channel_close_respond(channel);
+
+       response->start_line.status_code = status_code;
+       synth_header->completion_cause = completion_cause;
+       mrcp_resource_header_property_add(response,SYNTHESIZER_HEADER_COMPLETION_CAUSE);
        return TRUE;
 }
 
-
 /** Process SPEAK request */
 static apt_bool_t flite_synth_channel_speak(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response)
 {
+       mrcp_generic_header_t *generic_header;
+       const char *content_type = NULL;
        flite_synth_channel_t *synth_channel = (flite_synth_channel_t *) channel->method_obj;
+       apt_task_msg_t *msg = 0;
+       flite_speak_msg_t *flite_msg = 0;
        apt_log(APT_LOG_MARK, APT_PRIO_INFO, "flite_synth_channel_speak - channel %d", synth_channel->iId);
 
-       if (!synth_channel->speak_request)
-       {
-               apt_task_msg_pool_t *msg_pool = apt_task_msg_pool_create_dynamic( sizeof(flite_speak_msg_t),synth_channel->pool);
-               apt_task_vtable_t       *task_vtable = 0;
-               apt_task_t * task = 0;
-               apt_task_msg_t *msg = 0;
-               flite_speak_msg_t *flite_msg = 0;
-
-               /* create task/thread to run flite so this function is not blocking */
-               apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "Create flite speak task - channel: %d", synth_channel->iId);
-           synth_channel->task = apt_consumer_task_create(synth_channel, msg_pool, synth_channel->pool);
-               if (!synth_channel->task) 
-               {
-                       apt_log(APT_LOG_MARK,APT_PRIO_ERROR, "flite_synth_channel_speak failed to create flite speak task - channel:%d", synth_channel->iId);
-                       return FALSE;
-               }
-
-               task_vtable = apt_consumer_task_vtable_get(synth_channel->task);
-               if (!task_vtable) 
-               {
-                       apt_log(APT_LOG_MARK,APT_PRIO_ERROR, "flite_synth_channel_speak cannot use flite speak task vtable - channel:%d", synth_channel->iId);
-                       return FALSE;
+       generic_header = mrcp_generic_header_get(request);
+       if(generic_header) {
+               /* content-type must be specified */
+               if(mrcp_generic_header_property_check(request,GENERIC_HEADER_CONTENT_TYPE) == TRUE) {
+                       content_type = generic_header->content_type.buf;
                }
+       }
+       if(!content_type) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Missing Content-Type");
+               synth_response_construct(response,MRCP_STATUS_CODE_MISSING_PARAM,SYNTHESIZER_COMPLETION_CAUSE_ERROR);
+               return FALSE;
+       }
 
-               task_vtable->process_msg = flite_speak;
-               synth_channel->speak_request = request;
-               
-               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG, "Start task - channel %d", synth_channel->iId);
-               task = apt_consumer_task_base_get(synth_channel->task);
-               if (apt_task_start(task) == FALSE) 
-               {
-                       apt_log(APT_LOG_MARK,APT_PRIO_ERROR, "flite_synth_channel_speak failed to start task - channel: %d", synth_channel->iId);
-                       apt_task_destroy(task);
-                       return FALSE;
-               }
+       /* Flite currently supports only text/plain (no SSML) */
+       if(strstr(content_type,"text") == NULL) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Not Supported Content-Type [%s]",content_type);
+               synth_response_construct(response,MRCP_STATUS_CODE_UNSUPPORTED_PARAM_VALUE,SYNTHESIZER_COMPLETION_CAUSE_ERROR);
+               return FALSE;
+       }
 
-               msg = apt_task_msg_acquire(msg_pool);
-               msg->type = TASK_MSG_USER;
-               flite_msg = (flite_speak_msg_t*) msg->data;
-               flite_msg->channel = synth_channel;
-               flite_msg->request = request;
-               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG, "Send signal to start speech synthesis - channel:%d", synth_channel->iId);
-               if (apt_task_msg_signal(task,msg))
-               {
-                       response->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS;
-                       mrcp_engine_channel_message_send(channel,response);
-               }
-               else
-               {
-                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING, "Failed to send signal to start speech synthesis - channel:%d", synth_channel->iId);
-                       apt_task_destroy(task);
-                       return FALSE;
-               }
+       synth_channel->speak_request = request;
+       synth_channel->speak_response = response;
+
+       msg = apt_task_msg_acquire(synth_channel->msg_pool);
+       msg->type = TASK_MSG_USER;
+       flite_msg = (flite_speak_msg_t*) msg->data;
+       flite_msg->channel = synth_channel;
+       flite_msg->request = request;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG, "Send signal to start speech synthesis - channel:%d", synth_channel->iId);
+       if(apt_task_msg_signal(synth_channel->task,msg) != TRUE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING, "Failed to send signal to start speech synthesis - channel:%d", synth_channel->iId);
+               synth_channel->speak_request = NULL;
+               synth_channel->speak_response = NULL;
+               synth_response_construct(response,MRCP_STATUS_CODE_METHOD_FAILED,SYNTHESIZER_COMPLETION_CAUSE_ERROR);
+               return FALSE;
        }
        return TRUE;
 }
@@ -444,62 +410,80 @@ static apt_bool_t flite_speak(apt_task_t *task, apt_task_msg_t *msg)
 {
        flite_speak_msg_t *flite_msg = (flite_speak_msg_t*)msg->data;
        flite_synth_channel_t *synth_channel = (flite_synth_channel_t *) flite_msg->channel;
+       cst_wave *wave = NULL;
+       cst_voice *voice = NULL;
        apr_time_t start = 0;
        apr_time_t elapsed = 0;
        apr_time_t stamp = 0;
+       apt_str_t *body;
+       mrcp_message_t *response;
 
-       mrcp_message_t *stop_response = 0;
        mpf_codec_t * codec = mrcp_engine_source_stream_codec_get(synth_channel->channel);
-       apr_uint16_t rate = codec->descriptor->sampling_rate;                   
+       apr_uint16_t rate = codec->descriptor->sampling_rate;
+       body = &synth_channel->speak_request->body;
+
+       response = synth_channel->speak_response;
+       synth_channel->speak_response = NULL;
 
        apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "< flite_speak_msg_process speak - channel %d", synth_channel->iId);
        
-       // just sequential stuff
+       /* just sequential stuff */
        start = apr_time_now(); // in microsec
-       if (synth_channel->speak_request->body.length)
-       {
-               // TODO 
-               // create small units of text from synth_channel->speak_request->body.buf ( , . ? ! but ...
-               // synthesize small unit and store in audio_buffer
-               // check for stop 
-               // pause resume state could improve performance 
-               // you can "pause" generating new speech from a unit of text 
-               // by checking the (decreasing) size of the audio_buffer
-               // no need to generate more speech samples than can be listened to...
-               cst_wave *wave = 0;
-               wave = flite_text_to_wave(synth_channel->speak_request->body.buf, synth_channel->voice);
-               if (wave && cst_wave_num_samples(wave)) 
-               {
-                       int generated = (cst_wave_num_samples(wave)/cst_wave_sample_rate(wave)*1000);
-                       stamp = apr_time_now();
-                       elapsed = (stamp - start)/1000;
-                       apt_log(APT_LOG_MARK, APT_PRIO_INFO, "TTS (chan %d) took %"APR_TIME_T_FMT" to generate %d of speech (in millisec)", synth_channel->iId, elapsed, generated);
-
-                       if (rate != 16000)
-                       {
-                               cst_wave_resample(wave, rate);
-                               elapsed = (apr_time_now() - stamp)/1000;
-                               apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "TTS resampling to %d on (chan %d) took %"APR_TIME_T_FMT" millisec", rate, synth_channel->iId, elapsed);
-                       }
-                       mpf_buffer_audio_write(synth_channel->audio_buffer, cst_wave_samples(wave), cst_wave_num_samples(wave) * 2);
-                       delete_wave(wave);
-               }
+       if(!body->length) {
+               synth_channel->speak_request = NULL;
+               synth_response_construct(response,MRCP_STATUS_CODE_MISSING_PARAM,SYNTHESIZER_COMPLETION_CAUSE_ERROR);
+               mrcp_engine_channel_message_send(synth_channel->channel,response);
+               return FALSE;
        }
 
-       apr_thread_mutex_lock(synth_channel->channel_guard);
-       stop_response = synth_channel->stop_response; 
-       apr_thread_mutex_unlock(synth_channel->channel_guard);
-
-       if (!stop_response)
-       {
-               // this will notify the callback that feeds the client that synthesis is complete
-               mpf_buffer_event_write(synth_channel->audio_buffer, MEDIA_FRAME_TYPE_EVENT);
-               apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "> flite_speak_msg_process speak - end of TTS - %d", synth_channel->iId);
+       voice = flite_voices_best_match_get(
+                                                       synth_channel->flite_engine->voices,
+                                                       synth_channel->speak_request);
+       if(!voice) {
+               /* error case: no voice found, appropriate respond must be sent */
+               synth_channel->speak_request = NULL;
+               synth_response_construct(response,MRCP_STATUS_CODE_METHOD_FAILED,SYNTHESIZER_COMPLETION_CAUSE_ERROR);
+               mrcp_engine_channel_message_send(synth_channel->channel,response);
+               return FALSE;
        }
-       else
-       {
-               apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "> flite_speak_msg_process speak - channel %d", synth_channel->iId);
+
+       /* 
+       TODO 
+       create small units of text from synth_channel->speak_request->body.buf ( , . ? ! but ...
+       synthesize small unit and store in audio_buffer
+       check for stop 
+       pause resume state could improve performance 
+       you can "pause" generating new speech from a unit of text 
+       by checking the (decreasing) size of the audio_buffer
+       no need to generate more speech samples than can be listened to...      
+       */
+
+       /* send in-progress response and start synthesizing */
+       response->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS;
+       mrcp_engine_channel_message_send(synth_channel->channel,response);
+       
+       synth_channel->synthesizing = TRUE;
+       wave = flite_text_to_wave(body->buf, voice);
+       if(wave && cst_wave_num_samples(wave)) {
+               int generated = (cst_wave_num_samples(wave)/cst_wave_sample_rate(wave)*1000);
+               stamp = apr_time_now();
+               elapsed = (stamp - start)/1000;
+               apt_log(APT_LOG_MARK, APT_PRIO_INFO, "TTS (chan %d) took %"APR_TIME_T_FMT" to generate %d of speech (in millisec)", synth_channel->iId, elapsed, generated);
+
+               if(rate != 16000) {
+                       cst_wave_resample(wave, rate);
+                       elapsed = (apr_time_now() - stamp)/1000;
+                       apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "TTS resampling to %d on (chan %d) took %"APR_TIME_T_FMT" millisec", rate, synth_channel->iId, elapsed);
+               }
+               mpf_buffer_audio_write(synth_channel->audio_buffer, cst_wave_samples(wave), cst_wave_num_samples(wave) * 2);
+               delete_wave(wave);
        }
+
+       // this will notify the callback that feeds the client that synthesis is complete
+       mpf_buffer_event_write(synth_channel->audio_buffer, MEDIA_FRAME_TYPE_EVENT);
+       synth_channel->synthesizing = FALSE;
+
+       apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "> flite_speak_msg_process speak - end of TTS - %d", synth_channel->iId);
        return TRUE;
 }
 
@@ -510,10 +494,7 @@ static apt_bool_t flite_synth_channel_stop(mrcp_engine_channel_t *channel, mrcp_
        apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_channel_stop - channel %d", synth_channel->iId);
        /* store the request, make sure there is no more activity and only then send the response */
 
-       apr_thread_mutex_lock(synth_channel->channel_guard);
        synth_channel->stop_response = response;
-       apr_thread_mutex_unlock(synth_channel->channel_guard);
-
        return TRUE;
 }
 
@@ -541,29 +522,6 @@ static apt_bool_t flite_synth_channel_resume(mrcp_engine_channel_t *channel, mrc
        return TRUE;
 }
 
-/** Callback is called from MPF engine context to destroy any additional data associated with audio stream */
-static apt_bool_t flite_synth_stream_destroy(mpf_audio_stream_t *stream)
-{
-       apt_log(APT_LOG_MARK, APT_PRIO_INFO, "flite_synth_stream_destroy");
-       return TRUE;
-}
-
-/** Callback is called from MPF engine context to perform any action before open */
-static apt_bool_t flite_synth_stream_open(mpf_audio_stream_t *stream)
-{
-//     flite_synth_channel_t *synth_channel = (flite_synth_channel_t *) stream->obj;
-//     apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_stream_open - channel %d", synth_channel->iId);
-       return TRUE;
-}
-
-/** Callback is called from MPF engine context to perform any action after close */
-static apt_bool_t flite_synth_stream_close(mpf_audio_stream_t *stream)
-{
-//     flite_synth_channel_t *synth_channel = (flite_synth_channel_t *) stream->obj;
-//     apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_stream_close - channel %d", synth_channel->iId);
-       return TRUE;
-}
-
 /** Raise SPEAK-COMPLETE event */
 static apt_bool_t flite_synth_speak_complete_raise(flite_synth_channel_t *synth_channel)
 {
@@ -602,26 +560,25 @@ static apt_bool_t flite_synth_speak_complete_raise(flite_synth_channel_t *synth_
 static apt_bool_t flite_synth_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame)
 {
        flite_synth_channel_t *synth_channel = (flite_synth_channel_t *) stream->obj;
-       if (synth_channel->stop_response && synth_channel->speak_request)
-       {
+       if(synth_channel->stop_response && synth_channel->synthesizing == FALSE) {
                /* send asynchronous response to STOP request */
-               mrcp_engine_channel_message_send(synth_channel->channel, synth_channel->stop_response);
+               mrcp_message_t *stop_response = synth_channel->stop_response;
+               synth_channel->stop_response = NULL;
                synth_channel->speak_request = NULL;
                synth_channel->paused = FALSE;
+               mrcp_engine_channel_message_send(synth_channel->channel,stop_response);
                return TRUE;
        }
 
        /* check if there is active SPEAK request and it isn't in paused state */
-       if (synth_channel->speak_request && synth_channel->paused == FALSE) 
-       {
+       if(synth_channel->speak_request && synth_channel->paused == FALSE) {
                /* normal processing */
                mpf_buffer_frame_read(synth_channel->audio_buffer,frame);
 //             apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_stream_read - channel %d - size %d", synth_channel->iId, mpf_buffer_get_size(synth_channel->audio_buffer));
 
-               if((frame->type & MEDIA_FRAME_TYPE_EVENT) == MEDIA_FRAME_TYPE_EVENT) 
-               {
+               if((frame->type & MEDIA_FRAME_TYPE_EVENT) == MEDIA_FRAME_TYPE_EVENT) {
                        flite_synth_speak_complete_raise(synth_channel);
                }
        }
        return TRUE;
-}
\ No newline at end of file
+}